﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-iniwf-随笔分类-图形图像多媒体</title><link>http://www.cppblog.com/iniwf/category/9829.html</link><description>风是温柔的，雨是伤心的，云是快乐的，月是多情的，爱是迷失的，恋是醉人的，情是难忘的，天是长久的，地是永恒的</description><language>zh-cn</language><lastBuildDate>Wed, 03 Jun 2009 02:23:08 GMT</lastBuildDate><pubDate>Wed, 03 Jun 2009 02:23:08 GMT</pubDate><ttl>60</ttl><item><title>DirectDraw 与 DirectInput 的游戏编程体验</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86490.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:54:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86490.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86490.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86490.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86490.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86490.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Abstract/DirectDraw">http://dev.gameres.com/Program/Abstract/DirectDraw</a>与DirectInput的游戏编程体验.htm<br><br>
<table id=AutoNumber2 style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width="85%" border=0>
    <tbody>
        <tr>
            <td width="100%">
            <p align=center><font color=#ffffee size=4><strong>DirectDraw 与 DirectInput 的游戏编程体验</strong></font></p>
            </td>
        </tr>
        <tr>
            <td width="100%">　</td>
        </tr>
        <tr>
            <td width="100%"><a href="file:///C:/Documents%2520and%2520Settings/lanier/妗岄潰/寰呭鐞嗘暟鎹甛寰愪紭鏂囩珷%25202003%5B1%5D.10.23/projects.zip"><u><font color=#0000ff>源代码下载（3个工程）</font></u></a> <font color=#ff0000>(编辑者：链接失效)</font>
            <p>　　我想关于这个主题的文章，不算少，但也不算太多。但大多是分别介绍 DirectDraw 与 DirectInput，而并没有将其结合起来，也许你会问：&#8220;分开与合并起来并没有本质区别啊！&#8221;。其实的确没有本质区别，但那样使那些最初对游戏编程报有极大热情的爱好者感到非常失望，因为这其中的一个并不能完全满足他们的要求，并且使其感到巨大的阻力，从而失去信心。所以本文将 DirectDraw 与 DirectInput结合起来去讲一个主题就是&#8220;游戏编程&#8221;，请注意是&#8220;游戏编程&#8221;，当然这只是一个简单的桌面游戏，但这已经与先前有很大的不同了，这已不是简单的 DirectDraw或 DirectInput编程。我想你现在应该能够体会出其中的区别了。</p>
            <p><font color=#ff0000>　　声明：在这之前需要你具有一定的 WIN32 API 函数的知识，并且可以熟练使用。和 DirectDraw的知识，关于DirectDraw可以参见 www.frontfree.net 中的 &lt;&lt;动画程序编写——DirectDraw之旅&gt;&gt; 1-3)，或其它文章。最后是 c++ 语言，当然也要包括面向对象的那部分。在 Visual C++ .NET 编译环境下进行开发的。</font></p>
            <p>　　首先 ，我们还是先简要复习一下DirectDraw的概念吧！<br>DirectDraw本质上是显存管理程序。它最重要的性能是允许程序员直接在显存里存储和操纵位图。它使你能够利用视频硬件bliter（位块传输器）在显存内部进行位图的blit（位块传输）。用视频硬件的blitter从显存向显存进行blit比从内存向显存更快。这在64位显卡向显存提供64位数据路径的今天显得尤其重要，硬件独立于促CPU进行位块传输操作，使得CPU得以继续工作。另外DirectDraw支持显卡的其他硬件加速特性，例如对精灵和z -buffering的硬件支持。</p>
            <p><strong>DirectDraw的工作原理</strong></p>
            <p>我们这里还是用图表方式展现给大家吧!</p>
            <p><img height=433 src="http://dev.gameres.com/Program/Abstract/DDandDIgame/image001.gif" width=505> </p>
            <p>　　细心的朋友可以很明显地注意到图示中的右上角的图解中说明，表面对象有两个宽度，一个是WIDTH，一个是PITCH。WIDTH就是创建表面时所给出的那个宽度，而PITCH是表面的实际宽度，是按字节算的。在许多显卡上，PITCH和WIDTH是相等的，比如在640x480的高彩模式下，PITCH为1280。而在某些显卡上，PITCH比WIDTH要大。比如在640x480的256色模式下，当WIDTH是640时，PITCH为1024而不是640，这些显卡这样做是为了更好地进行数据对齐来提高性能或达到其它目的。所以，我们在实际编程时，为了保证程序的兼容性，必须按PITCH处理。 但这些硬件的底层问题，我们不用太关心，只要稍有了解就可以了。</p>
            <p><strong>下面我们再简要叙述一下，如何使用 DirectX 9.0 中提供的 DirectDraw 类库来创建对象并使用操作对象。</strong></p>
            <p>宏定义在先，定义删除指针和释放对象的宏</p>
            <table class=code cellSpacing=1 cellPadding=0 width="100%" bgColor=#e0e0e0 border=0>
                <tbody>
                    <tr>
                        <td>
                        <p class=lc><font color=#0000ff>#define</font> <font color=#000000>SAFE_DELETE(p) { </font><font color=#0000ff>if</font><font color=#000000>(p) { </font><font color=#0000ff>delete</font><font color=#000000> (p); (p)=NULL; } }</font><br><font color=#0000ff>#define</font><font color=#000000> SAFE_RELEASE(p) { </font><font color=#0000ff>if</font><font color=#000000>(p) { (p)-&gt;Release(); (p)=NULL; } }</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <p>先创建一个 CDisplay 的全局对象<br>CDisplay就是ddutil.h中定义的类，用于处理表面之间的拷贝翻页等操作的类，再次定义一个全局变量，用于以后对指向的表面之间进行操作</p>
            <table class=lc cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>CDisplay* g_pDisplay = NULL;</font></td>
                    </tr>
                </tbody>
            </table>
            <p>然后创建表面，当然可以创建很多的表面，这些表面都是离屏表面，在更新画面时，都可以用 CDisplay 类的对象中的方法，将其拷贝到后备缓冲区表面上。只要创建离屏表面，就要用到 CSurface 类。CSurface也是ddutil.h头文件中定义的类，用于对表面本身进行操作，如设置色彩键码，在此定义的图画指针。<br>　</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>CSurface* g_pBackSurface = NULL;</font></td>
                    </tr>
                </tbody>
            </table>
            <p>DirectX 中就一共用这两个类封装了 DirectDraw 对象的大部分操作，如果你觉得这还不能满足要求，那么你也可以在程序中用 DirectDraw API 函数编写程序，不过在本文中不再介绍。</p>
            <p>这之后，我们会用到 InitDirectDraw 函数。这个函数是我们自己创建的。在此函数中作所有的 DirectDraw 的对象初始化工作。</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>HRESULT InitDirectDraw( HWND hWnd )<br>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT hr; </font><font color=#006600>//接受返回值，其实是long型变量</font> <br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPDIRECTDRAWPALETTE pDDPal = NULL; </font><font color=#006600>//定义程序中的调色板</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int</font><font color=#000000> iSprite;</font> <font color=#006600>//定义与sprite个数有关的计数器</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_pDisplay = </font><font color=#0000ff>new</font> <font color=#000000>CDisplay();</font> <font color=#006600>//动态开辟一个CDisplay类</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;CreateFullScreenDisplay( hWnd, SCREEN_WIDTH, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SCREEN_HEIGHT, SCREEN_BPP ) ) )</font> <font color=#006600>/*设置程序为全屏，并且 g_pDisplay 就是动态开辟一个CDisplay类的指针，而在这个类的域中，有一个DirectDraw主表面指针，和一个后备缓冲区表面的指针。在从我建议你可以先去阅读一下 ddutil.h 和 ddutil.cpp 文件。*/</font><br>&nbsp;&nbsp;<font color=#000000>&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox( hWnd, TEXT("This display card does not support 1024x768x8. "),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font><font color=#000000> hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;CreatePaletteFromBitmap( &amp;pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )</font> <font color=#006600>//顾名思义，就是从bmp图片中获得调色板值，并赋值在pDDPal结构指针所指向的结构体中。</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;SetPalette( pDDPal ) ) )</font> <font color=#006600>//用刚才从IDB_DIRECTX中获得的调色板制来设置程序调色板</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAFE_RELEASE( pDDPal );</font><font color=#006600>//释放指针，在用过后，一定要释放，这是良好的编程习惯</font><br><font color=#006600>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 用IDB_WINXP图片创建一个表面，并用g_pBackSurface指向这个表面<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;CreateSurfaceFromBitmap( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;g_pBackSurface, MAKEINTRESOURCE( IDB_WINXP ), <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SCREEN_WIDTH, SCREEN_HEIGHT ) ) )</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font><font color=#000000> hr;</font><font color=#006600>//设置色彩键码为黑色，0代表黑色，这样在表面的拷贝过程中黑色像素的点将不会被拷贝，这样可以产生镂空效果。当然你可以任意设置关键颜色，而颜色的表示法可以用 RGB 宏定义。例如 红色：RGB( 255,0,0 ), 黑色 RGB( 255,255,255 )<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = g_pBackSurface-&gt;SetColorKey( RGB( 255,255,255 ) ) ) )</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>S_OK;<br>}</font></td>
                    </tr>
                </tbody>
            </table>
            <p>下面的函数是用于更新画面的。<br>　</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>HRESULT DisplayFrame()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_pDisplay-&gt;Clear( 0 ); </font><font color=#006600>//清空后备缓冲区表面</font><br><font color=#006600>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//将g_pBackSurface所指向的图片拷贝到后备缓冲区表面</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_pDisplay-&gt;Blt( 0, 0, g_pBackSurface, NULL );</font><font color=#006600>//最关键的地方在这里，请看下面的语句，只要我们一执行翻页操作，就可以将改动了的图像了显示在屏幕上了<br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;Present()</font> <font color=#006600>/*翻页操作*/</font><font color=#000000>) )</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>S_OK;</font><br><font color=#000000>}</font></td>
                    </tr>
                </tbody>
            </table>
            <p>下面的函数是用于在程序失去焦点时调用的。</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>HRESULT RestoreSurfaces()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPDIRECTDRAWPALETTE pDDPal = NULL;</font> <font color=#006600>/*当程序失去焦点，要保存当前的画面，请注意这里，g_pDisplay-&gt;GetDirectDraw()函数返回的才是真正的 DirectDraw 对象 */<br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;GetDirectDraw()-&gt;RestoreAllSurfaces() ) )</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;</font><font color=#006600>//在此我们还要重新创建调色板<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;CreatePaletteFromBitmap( &amp;pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;</font><font color=#006600>//重新设置调色板<br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>if</font><font color=#000000>( FAILED( hr = g_pDisplay-&gt;SetPalette( pDDPal ) ) )</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAFE_RELEASE( pDDPal );</font><font color=#006600>//重新画出图画<br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>if</font><font color=#000000>( FAILED( hr = g_pLogoSurface-&gt;DrawBitmap( MAKEINTRESOURCE( IDB_WINXP ),<br>SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#0000ff>return</font> <font color=#000000>hr;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>S_OK;<br>}</font></td>
                    </tr>
                </tbody>
            </table>
            <p>下面这个函数是释放表面指针所用的。</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>VOID FreeDirectDraw()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAFE_DELETE( g_pBackSurface );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAFE_DELETE( g_pDisplay );<br>}</font></td>
                    </tr>
                </tbody>
            </table>
            <p>我们的回顾到此结束，下面我们开始本文要介绍的一个关键技术，DirectInput 的使用。<br>游戏编程可不仅仅是图形程序的开发工作，实际上包含了许多方面，本文所要讲述的就是关于如何使用 DirectInput 来对键盘编程的问题。<br>而我们为什么要选择用 DirectInput 来处理游戏中的输入问题呢？其实用 Win32 API 函数也完全可以处理这些工作，例如其中，有一个 </p>
            <p>GetAsyncKeyState() 的函数可以返回一个指定键的当前状态是按下还是松开。这个函数还能返回该指定键在上次调用 GetAsyncKeyState() 函数以后，是否被按下过。虽然这个函数听上去很不错，但需要我们自己轮换查询每个键盘的状态。而在 DirectInput 中我们已经可以脱离这些烦琐的工作，只因它的功能更强大。</p>
            <p>由于本文重点在二者的结合，故在此只介绍 DirectInput 中比较简单的，而且最容易上手的立即模式的工作方式。<br>而这里我们要用到 DirectInput 的 API 函数。有人会问，为什么在 DirectDraw 中用 DirectX 提供的类库编程，而对于 DirectInput 却直接使用要用其 API 函数呢，是因为没有提供 DirectInput 的类库吗？不是！而是因为使用类库并不很方便而且不灵活。</p>
            <p>OK，让我们开始我们游戏编程的第二部——DirectInput编程。</p>
            <p>前面讲 DirectDraw 时，并没有提到，微软是按 COM 来设计DirectX的，所以就有了一个 DIRECTINPUT 对象来表示输入设备，而某个具体的设备由 DIRECTINPUTDEVICE 对象来表示。也许会感到很无奈，怎么游戏编程需要这么多的知识啊，其实您也无需烦恼，只要知道一下就可以了，其实这并不；影响您的设计，而且就算您不知道，也同样可以驾驭DIRECTINPUT。</p>
            <p>实际的建立过程是先创建一个 DIRECTINPUT 对象，然后在通过此对象的 CreateDevice 方法来创建 DIRECTINPUTDEVICE 对象。</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=lc><font color=#0000ff>#include</font><font color=#000000> &lt;dinput.h&gt;</font><br><font color=#0000ff>#define</font> <font color=#000000>DINPUT_BUFFERSIZE 16<br>LPDIRECTINPUT lpDirectInput; </font><font color=#006600>// DirectInput 对象实际上是一个com对象</font><br><font color=#000000>LPDIRECTINPUTDEVICE lpKeyboard; </font><font color=#006600>// DirectInput 设备<br></font><font color=#000000>BOOL InitDInput(HWND hWnd)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT hr;</font><font color=#006600>// 创建一个 DIRECTINPUT 对象<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = DirectInputCreate(hInstanceCopy, DIRECTINPUT_VERSION, &amp;lpDirectInput, NULL)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><font color=#006600>// 失败提示或处理</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font> <font color=#0000ff>&nbsp;return</font> <font color=#000000>hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><font color=#006600>// 创建一个 DIRECTINPUTDEVICE 界面<br>//参数 GUID_SysKeyboard 指明了建立的是键盘对象</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = lpDirectInput-&gt;CreateDevice(GUID_SysKeyboard, &amp;lpKeyboard, NULL)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>// 失败提示或处理</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><font color=#006600>// 设定为通过一个 256 字节的数组返回查询状态值</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED(hr = lpKeyboard-&gt;SetDataFormat(&amp;c_dfDIKeyboard)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>// 失败提示或处理</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font><font color=#000000> hr;</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><font color=#006600>// 设定协作模式为独占模式和前台模式，独占模式表面本程序在运行中占有所有键盘资源，而前台模式指出当程序具有焦点时才可以占有键盘资源</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( hr = lpKeyboard-&gt;SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>// 失败提示或处理</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><br><font color=#006600>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 设定缓冲区大小<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 如果不设定，缓冲区大小默认值为 0，程序就只能按立即模式工作<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 如果要用缓冲模式工作，必须使缓冲区大小超过 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 在此，我们没有必要设定，因为我们就用立即模式工作（还有一种缓冲模式）,所有我们将其注调了</font></p>
                        <p><font color=#006600>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* DIPROPDWORD property;</font></p>
                        <p><font color=#006600>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.diph.dwSize = sizeof(DIPROPDWORD);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.diph.dwHeaderSize = sizeof(DIPROPHEADER);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.diph.dwObj = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.diph.dwHow = DIPH_DEVICE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.dwData = DINPUT_BUFFERSIZE;</font></p>
                        <p class=lc><font color=#006600>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( FAILED(hr = lpKeyboard-&gt;SetProperty(DIPROP_BUFFERSIZE, &amp;property.diph)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 失败<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>return FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</font><br><font color=#006600>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//此处是关键，我们要通过这个函数来锁定键盘，记住，所有的DirectInput资源在使用前都要锁定，在此即获得键盘资源，在知识我们刚才设定的键盘模式才能起作用<br></font><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr = lpKeyboard-&gt;Acquire();</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000> FAILED(hr)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>// 失败</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font><font color=#000000> FALSE;</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font> <font color=#0000ff>return</font> <font color=#000000>TRUE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <p>在这段代码中，我们首先定义了 lpDirectInput 和 lpKeyboard 两个指针，前者指向 DIRECTINPUT 对象，后者指向一个 </p>
            <p>DIRECTINPUTDEVICE 界面。其顺序就是这样的。这和其它COM对象的使用方法都一样，即先创建 COM 对象，然后创建界面，然后再获得<br>硬件资源，然后使用资源，然后释放。</p>
            <p>通过 DirectInputCreate(), 我们为 lpDirectInput 创建了一个 DIRECTINPUT 对象。然后我们调用 CreateDevice 来建立一个DIRECTINPUTDEVICE 界面。<br>　　<br>完成这些工作以后，我们便调用 DIRECTINPUTDEVICE 对象的 Acquire 方法来激活对设备的访问权限。在此要特别说明一点，任何一个 </p>
            <p>DIRECTINPUT 设备，如果未经 Acquire，是无法进行访问的。还有，当系统切换到别的进程时，必须用 Unacquire 方法来释放访问权限，在系统切换回本进程时再调用 Acquire 来重新获得访问权限。</p>
            <p>立即模式的数据查询</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>HRESULT ReadImmediateData( HWND hWnd )<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HRESULT hr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BYTE diks[256];</font> <font color=#006600>// 创建键盘状态数据缓冲区存取键盘信息</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int</font> <font color=#000000>i; </font><font color=#006600>// 计数器</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( NULL == g_pKeyboard ) </font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>S_OK;</font><font color=#006600>// 键盘状态数据缓冲区清0</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#000000>ZeroMemory( &amp;diks, </font><font color=#0000ff>sizeof</font><font color=#000000>(diks) );</font><font color=#006600>// 获得键盘所有键的信息，这只是检查一次</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#000000>hr = g_pKeyboard-&gt;GetDeviceState( </font><font color=#0000ff>sizeof</font><font color=#000000>(diks), &amp;diks );</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED(hr) ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>// 如果键盘资源丢失，我们要重新获得</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr = g_pKeyboard-&gt;Acquire();</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while</font><font color=#000000>( hr == DIERR_INPUTLOST ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hr = g_pKeyboard-&gt;Acquire();</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>S_OK; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><font color=#006600>// 进行一下轮循，处理键盘信息。</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for</font><font color=#000000>( i = 0; i &lt; 256; i++ ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( diks[i] &amp; 0x80 ) </font><font color=#006600>//记录此键的状态，低字节最高位是 1 表示按下，0 表示松开，一般用 diks[i]&amp;0x80 来测试</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ </font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch</font><font color=#000000>(i)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>//我们可以通过测试计数器i，来判断是哪个键被按下了。<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>//我们提供几个数据 UP：200 down：208 left：203 right：205 enter：28 space：57<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>//其实你可以用DirectX中的Samples\C++\DirectInput\Bin\Keyboard.exe程序来测试，只不过那是用<br></font><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>//16进制显示的。</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case</font> <font color=#000000>200:</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case</font> <font color=#000000>0xc8:</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font> <font color=#000000>S_OK;<br>}</font></td>
                    </tr>
                </tbody>
            </table>
            <p>请注意，上面的这段代码只是一个示例，重在使你明白其原理，但并不能满足游戏的需求，因为这其中只查询了一次键盘的全部信息，做了一次轮循，而在游戏中要周期性地查询，并轮循，这就需要你自己用Win32 API函数 SetTimer和 KillTimer 设置初始化 DirectInput 对象函数中在相应的地方设置计计时器，让windows定时向程序发送 WM_TIMER消息，你要通过此消息进行周期性地键盘查询，并在相应的地方解除计时器。</p>
            <p>最后一个函数是用于释放指针或DirectInput对象的</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#0000ff>void</font><font color=#000000> ReleaseDInput(void)<br>{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font> <font color=#000000>(lpDirectInput)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>(lpKeyboard)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>// Always unacquire the device before calling Release().</font><br><font color=#0000ff>&nbsp;</font><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpKeyboard-&gt;Unacquire();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpKeyboard-&gt;Release();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpKeyboard = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpDirectInput-&gt;Release();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lpDirectInput = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</font></td>
                    </tr>
                </tbody>
            </table>
            <p>在这些函数中的注释很明确，关键在于理解其原理，而怎样将他们融入到 Win32 API 程序的基本框架中的，在&lt;&lt;动画程序编写——DirectDraw之旅&gt;&gt; 1-3中的示例代码中已经解释得很明确了，在此不再赘述。不过我们提供其中的代码示例下载。同时你也可以去仔细阅读DirectX 8.0 SDK 包中的 <font color=#99ccff>samples\ multimedia\ directdraw\ fullscreenmode</font> 或<font color=#006600> </font><font color=#99ccff>\ samples\ multimedia\ directdraw\ windowedmode</font> 这两个工程中的文件，因为为了我们的示例也是照这两个工程改编过来的，读者可以通过仔细阅读代码和对比我们的更改，而更加了解 DirectDraw的运行运行原理。（请注意：是 DirectX 8.0 SDK 包中的示例，而在 9.0 中 DirectX SDK 已经不提供 DirectDraw的示例代码了）</p>
            <p>我们就用这七个函数就已经可以创造出一个小游戏了。</p>
            <p>我们下面就要利用&lt;&lt;动画程序编写——DirectDraw之旅&gt;&gt; 1-3 中所用的代码进行进一部的游戏开发。<br>我们先展示一下 DirectX中<font color=#99ccff>\ samples\ multimedia\ directdraw\ windowedmode </font>工程中的截图<br>在这个动画中有黑色背景，并有很多 DirectX 精灵在漂浮。</p>
            <p><img height=301 src="http://dev.gameres.com/Program/Abstract/DDandDIgame/image002.jpg" width=400><br><br>这是一个全屏的动画程序，而我们在&lt;&lt;动画程序编写——DirectDraw之旅&gt;&gt; 1-3其中做的改动就是为其加了一个背景，改屏幕分辨率 640&#215;480 为 1024&#215;768.注意，因为我们应用的是全屏模式，即可以独占显存资源，所以我们可以更改屏幕的分辨率。这只是做的小小的改动，而我们的目的只在于让大家更加深入了解。且看下面的这副截图：</p>
            <p><img height=300 src="http://dev.gameres.com/Program/Abstract/DDandDIgame/image004.jpg" width=400></p>
            <p>而我们还要继续深入编程，我们的思路是，先将程序由先前的全屏程序改编成一个windows的窗口程序，然后将其所有的界面翻新，并改编 DirectX精灵为许多小蘑菇在漂浮，还要加入DirectInput 的组建，用键盘控制一个小娃娃。可以上下左右，并可以斜向飞行。<br>我们先将此动画的截图展现给大家</p>
            <p><img height=320 src="http://dev.gameres.com/Program/Abstract/DDandDIgame/image006.jpg" width=400></p>
            <p>怎么样，你有什么想法，是想说：&#8220;唉，这还不好办，就是又多加了一个！&#8221;，但不要光看截图，不要忘记，我们一定让她动起来，并且是可以控制的，这就不是那么简单的事了！<br>什么？若有人看到这里感到有些迷茫和泄气，不禁想问：&#8220;你说了这么多，那么源代码在那里呢！，光给我们几个函数，又能做什么呢？&#8221;，如果你这么想，你也不要太急迫。我们还是先分析一下程序框架吧。</p>
            <p>不过，还有一件重要的事情，我还是要重申一边。一定要将 DirectX 的头文件价，和lib文件夹加入到 Visual C++.NET 的默认目录中去，这样编译器就可以正确地找到它们了。<br>如果你不会加入，就请通过工具栏上的 Tool -&gt; Option&#8230; 打开Option 对话框，设置如图：</p>
            <p><img height=320 src="http://dev.gameres.com/Program/Abstract/DDandDIgame/image008.jpg" width=550><br><br>好了，这样我们的准备工作就算已经做好了。</p>
            <p>来看看我们的工程文件结构吧，还有工程中的资源。</p>
            <p><img height=328 src="http://dev.gameres.com/Program/Abstract/DDandDIgame/image010.jpg" width=211> <img height=329 src="http://dev.gameres.com/Program/Abstract/DDandDIgame/image011.jpg" width=214></p>
            <p>在工程资源中我们的 ID 号是都用的字符串表示的，笔者认为这样更加方便。<br>我想对于工程文件中的 ddutil.cpp 和 dxutil.cpp 文件，读者如果了解有些 DirectDraw编程是不会感到陌生的，我们只是将其引入到我们的工程中了。而我们自己实际编程的文件是<br>outfly.cpp 文件。</p>
            <p>我们的程序叙述如下：<br>首先进行宏定义，结构设置，和全局变量的声明。<br>后在 WinMain （windows程序的入口点）中首先初始化一切需要初始化的物件（有windows窗口，DirectDraw对象，和 DirectInput对象），在此我们就调用前文讲过的函数，但要有写改动，读者在会在后面看到的。然后进入消息循环，在其中没有消息时，程序会自动更新画面，在有消息时处理消息。<br>当遇到 WM_QUIT 消息后，结束整个程序。</p>
            <p>我们在一些地方有一些小小的改动，我们来看看吧。</p>
            <p><strong>1</strong> 我们在 HRESULT InitDirectInput( HWND hWnd )<br>函数中的开始加入了</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>KillTimer( hWnd, 0 ); <br>FreeDirectInput();</font></td>
                    </tr>
                </tbody>
            </table>
            <p>关掉上一次使用的计时器，并释放 DirectInput 设备。<br>而在最后加入了</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#000000>SetTimer( hWnd, 0, 1000 / 100, NULL );</font></td>
                    </tr>
                </tbody>
            </table>
            <p>用来重新设置计时器。</p>
            <p><strong>2</strong> 我们在主窗口的消息处理函数中加入了</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0><font color=#0000ff>case</font><font color=#000000> WM_ACTIVATE: </font><font color=#006600>//当程序先失去焦点，而现在有重新得到焦点时，要重新锁定键盘资源</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( WA_INACTIVE != wParam &amp;&amp; g_pKeyboard )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#006600>// Make sure the device is acquired, if we are gaining focus.</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_pKeyboard-&gt;Acquire();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#0000ff>case</font> <font color=#000000>WM_TIMER:</font><font color=#006600> //因为设置了计时器所以要处理此消息</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( FAILED( ReadImmediateData( hWnd ) ) )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KillTimer( hWnd, 0 ); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox( NULL, _T("Error reading input state. ")<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_T("The sample will now exit."), <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_T("Keyboard"), MB_ICONERROR | MB_OK );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#0000ff>case</font> <font color=#000000>WM_DESTROY:</font><font color=#006600>// Cleanup and close the app</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeDirectDraw();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeDirectInput();</font> <font color=#006600>// 释放资源</font><br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PostQuitMessage( 0 );</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return</font><font color=#000000> 0L;</font></td>
                    </tr>
                </tbody>
            </table>
            <p><strong>3</strong> 在HRESULT ReadImmediateData( HWND hWnd ) 函数中进行了这样的处理，来时时改变小娃娃的坐标。</p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=lc bgColor=#e0e0e0><font color=#0000ff>for</font><font color=#000000>( i = 0; i &lt; 256; i++ ) <br>{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( diks[i] &amp; 0x80 ) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch</font><font color=#000000>(i)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case</font> <font color=#000000>200: </font><font color=#006600>//上键</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( g_me.fPosY &gt; g_me.fVelY)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_me.fPosY -= g_me.fVelY;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#000000>&nbsp;g_me.fPosY = 0;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case</font> <font color=#000000>208: </font><font color=#006600>//下键</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( g_me.fPosY &lt;= WINDOW_HEIGHT - SPRITE_DIAMETER - g_me.fVelY)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_me.fPosY += g_me.fVelY;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#000000>&nbsp;&nbsp;&nbsp;g_me.fPosY = WINDOW_HEIGHT- SPRITE_DIAMETER;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case</font> <font color=#000000>203:</font><font color=#006600>//左键</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( g_me.fPosX &gt; g_me.fVelX)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_me.fPosX -= g_me.fVelX;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#000000>&nbsp;&nbsp;&nbsp;g_me.fPosX = 0;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case</font> <font color=#000000>205:</font><font color=#006600>//右键</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if</font><font color=#000000>( g_me.fPosX &lt;= WINDOW_WIDTH - SPRITE_DIAMETER - g_me.fVelX)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g_me.fPosX += g_me.fVelX;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;g_me.fPosX = WINDOW_WIDTH- SPRITE_DIAMETER;</font><br><font color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break</font>;<br><font color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</font></td>
                    </tr>
                </tbody>
            </table>
            <p>这些只是其中一些比较重要的改动，还有许多改动，读者会在实际的程序中看到的。如果你觉得：&#8220;啊！到这里就结束了，可是我还是感到似乎莫不到头绪，就这样草草收尾了？&#8221;，其实文章并没有结束，重头戏还在后面呢，那就不是我的工作了，而是看你有没有耐心去仔细阅读代码了，因为想要把握程序的整体，与其让我将代码放在文章中，还不如读者自己在编译器中自己运行实践一下好，其实我们已经在第二个工程代码中有过详细的解释。但记住一定要按照顺序阅读 工程1，工程2 ，工程3。工程1就是 DirectX中提供的原代码，工程2就是我们改了一个背景的工程，而3就是我们讨论的工程。</p>
            </td>
        </tr>
        <tr>
            <td width="100%">　</td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86490.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:54 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86490.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DirectDraw编程基础</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86488.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:43:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86488.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86488.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86488.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86488.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86488.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DDrawBase1.htm">http://dev.gameres.com/Program/Visual/2D/DDrawBase1.htm</a><br><br>
<table id=table2 style="BORDER-COLLAPSE: collapse" cellPadding=0 width="100%" border=0>
    <tbody>
        <font face=Arial>
        <tr>
            <td bgColor=#f7ebde>
            <p align=center><font color=#000000><strong>DirectDraw编程基础</strong></font></p>
            </td>
            <td width=24 background=../../../../images1/frame/right.gif>　</td>
        </tr>
        <tr>
            <td width=21 background=../../../../images1/frame/left.gif>　</td>
            <td bgColor=#f7ebde><font class=NewsContent2><br>　　本文面向有几个月学习编程经历的初学者：看过C++的教程，看的懂基本的C++语法;有点点VC使用经验，知道怎么去组建一个工程；理解一些windows编程的基本概念，比如窗口、消息循环等；还有，不懂的地方会去查资料：）。<br>　　看过几本关于DirectDraw的书，这些书都不错，在此感谢她们的作者。美中不足的是这些书的部分起点较高，虽然我们仍然能够清晰的理解一些概念，但在组织这些文件上会有不少困惑。在此我重申一下书中的概念，也借此梳理一下自己的思路。废话少说，言归正传。<br>首先说一些不可不说的东西。我认为它们不可不提，是因为这些东西也许太基础，高手们往往忽略这些东西对新手的作用。作为一个新手，我觉得掌握程序的框架及组织方法，比多熟悉几个APIs更迫切一些。Now lets begin：<br>　　写一个游戏程序，要熟悉其流程，另外要锻炼组织程序文件的能力。对新手来说，我建议按部就班的来处理及分析要写的程序，不主张这个时候你在搞思维跳跃。这是个良好的习惯，当然也有利于我们尽快掌握编程的思想方法。下面来看一个概括的流程及相应的程序框架 <br><br>（框架显示不出来。。）<br><br>　　那么，如何利用上面的流程来构建我们的大体程序框架呢？<br><br>　　我们已经知道一些windows编程方面的东西了，也许你还比较了解MFC。我们这里不提倡用MFC，尽管它封装了好多有用的模式，但对我们编游戏来说，倒是累赘了。好，接着说。既然采用windowsAPI，可以建立个文件WinMain.cpp来处理windows编程中有关窗口的一些问题。这样，我们在该文件中应该完成创建窗口，处理基本消息（比如按&#8220;esc&#8221;退出等），控制程序退出等。游戏过程中窗口的消息是不是也要在这处理呢？当然，不过游戏当中的窗口就不仅是windows窗口了，显示部分要靠DirectDraw来控制，那么我们只好在WinMain.cpp中调用相关的模块来处理。这么看来，在WinMain.cpp中几乎囊括了整个流程,不错，它就控制了程序的整个框架，为你的程序内核提供了一个平台。平台有了，那么下一步，GameMain.cpp要诞生了，这个主要用来控制整个游戏的各个组件，协调各部分工作，完成游戏设置初始化，游戏中消息循环，控制游戏退出。你的才华就在这儿来尽情的发挥了。一般，游戏程序会有几个固定的组件的：显示，音乐，信息输入。在DirectX中提供了很方便的组件DirectDraw，DirectSound和DirectMusic，DirectInput。相应的我们建立MyDirectDraw.cpp，MyDirectAudio.cpp，MyDirectInput.cpp来控制各部分组件的相应功能。<br>显然，这3部分都是为GameMain.cpp服务的，被GameMain.cpp调用。那么我们可以看出我们的程序应该包括的文件及其包含关系为：<br><br>（图表显示不出来了，555）<br><br>　　程序文件怎么去组织，应该由这个表可以看出来。这么一看，我们发现，WinMain.cpp好像是一个投资者，提供开发平台，他只关注整个项目总的进程，不关注细节。GameMain.cpp好像个项目负责人，整个项目的细节过程由他来策划，来控制，向上与WinMain.cpp交互，来完成项目，向下协调MyDirectDraw.cpp，MyDirectAudio.cpp，MyDirectInput.cpp之间的工作。MyDirectDraw.cpp，MyDirectAudio.cpp，MyDirectInput.cpp这三个家伙就是员工了，负责各自的工作，完成相应的功能给GameMain.cpp。<br><br>　　组织程序应该就是这么个思路，当然具体问题具体分析。那么我们下面来开始看DirectDraw部分了。<br><br>　　首先，做准备工作，安装DirectX SDK，在VC中添加dxguid.lib和ddraw.lib（本来不想说这个，看到有个教程，它少加了dxguid.lib，郁闷了我好一阵子，害人颇深感觉）这样，directdraw程序才能通过编译。提一下，dxguid.lib中定义了DirectX中会用到的所有全局句柄，ddraw.lib是DirectDraw使用的函数库。<br><br>下面就可以写代码了，这里我们当然主要看MyDirectDraw.cpp该怎么写了<br>为此，我选出了几个源代码，做参考研究，它们会与本文一起打包。<br>我还是习惯先从整体上鸟瞰一下：<br><br>　　一般，在MyDirectDraw.cpp(注意不要忘记引用头文件ddraw.h)中至少要有两部分：初始化和结束。先看初始化，所谓初始化无非是个准备工作，需要的东西定义创建出来摆在手边以备后用。来看看初始化函数intMyDirectDrawInit（void）该怎么写。首先定义一个指向DirectDraw对象的指针，创建DirectDraw对象，查询以获取最新的DirectDraw接口，设置协作等级，设置显示模式。通过这些步骤可以创建一个黑色的屏幕了，也就是说已经开辟了我们需要的空间了，当然DirectDraw程序的初始化不会这么简单。要操作2d图形，我们还要接着创建主页面和缓冲页面以及离屏页面，总之根据需要，凡是需要在操作前需要准备好的东西都可以放在这里。那么结束 int MyDirectDrawShut（void）就应该释放我们开辟的东西，一般要释放主页面指针，和DirectDraw接口等。<br><br>大体就是这么个样子，go on，该细一点了，呵呵<br><br><font color=#000000>先定义指针：LPDIRECTDRAW lpDDraw_temp；代表整个显示系统<br>创建对象： if (FAILED(DirectDrawCreate(NULL, &amp;lpDDraw_temp, NULL)))<br>{<br>&nbsp;&nbsp;&nbsp; MessageBox(NULL,TEXT("Direct Draw Create error!"),<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>TEXT("Wrong!"),MB_OK);<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>return(0);<br>}<br></font><br>这里用了一个FAILED宏来检测是否创建成功，这可以帮我们跟踪错误。<br><br>函数DirectDrawCreate(NULL, &amp;lpDDraw_temp, NULL)完成创建，第一个参数是显示驱动的全局唯一标志符，这里null表示目前的显示设备；第二个参数用来接受创建出来的DirectDraw对象地址，这里用&amp;lpDDraw_temp接受；第三个参数？不要问，就给它null，不想惹麻烦的话。<br><br><font color=#000000>查询DirectDraw接口：if(FAILED(lpDDraw_temp-&gt;QueryInterface(IID_IDirectDraw7, (LPVOID *)&amp;lpDDraw7)))<br>{<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>MessageBox(NULL,TEXT("DirectDraw QueryInterface error!"),<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>TEXT("Wrong!"),MB_OK);<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>return(0);<br>}</font><br><br>通过QueryInterface()方法来获取新接口，这里是IDirectDraw7而不是IDirectDraw8，指向IDirectDraw7的指针放在lpDDraw7中，这是个全局变量，可以这样定义LPDIRECTDRAW7 lpDDraw7＝NULL；<br><br>顺便说一下，一般情况下你是应该知道你使用的接口的，这和SDK有关，所以说这一步不是必须的。<br><br><font color=#000000>设置协作等级： if (FAILED(lpDDraw7-&gt;SetCooperativeLevel(main_window_handle, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))<br>{<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>MessageBox(NULL,TEXT("DirectDraw SetCooperativeLevel error!"),<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>TEXT("Wrong!"),MB_OK);<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>return(0);<br>}</font><br><br>决定你这个程序和windows的关系，它向windows申请所用资源，比如它要全屏，独占等。第一个参数是主窗口句柄，就是你WinMain（）中创建的那个了，第二个参数有几个控制标志，常用的用法如下：<br><br><font color=#000000>DDSCL_FULLSCREEN：全屏模式，必须和DDSCL_EXCLUSIVE同时使用<br>DDSCL_EXCLUSIVE：请求独占级别，须和DDSCL_FULLSCREEN同时使用<br>DDSCL_ALLOWREBOOT：允许系统检测ctrl+alt+del按键消息（这很有用）</font><br><br>我想，这三个就够用了，其他的就先不用管了<br><font color=#000000>设置显示模式：if(FAILED(lpDDraw7-&gt;SetDisplayMode(800, 600, 16,0,0)))<br>{<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>MessageBox(NULL,TEXT("DirectDraw SetDisplayMode error!"),<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>TEXT("Wrong!"),MB_OK);<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>return(0);<br>}<br></font><br>游戏中要使用的显示模式可能和用户当前显示模式不一样，要在此统一设置SetDisplayMode（）强制使用它设置的模式，它的前三个参数很容易懂吧，第四个，用0表示使用默认的刷新率，第五个参数这里是0，有书上说必须用DDSDM_STANDVGAMODE（可以理解，只是不知道这个0什么意思，我想应该是default的意思吧。<br><br>到此为止，我想已经创建出来我们需要的空间了，以后，随着我们要求的提高，再逐步完善初始化函数，now看看结束函数：<br><font color=#000000>释放接口： if (lpDDraw7)<br>{<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>lpDDraw7-&gt;Release();<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>lpDDraw7 = NULL;<br>}<br></font><br>以后还要释放主页面，缓冲页面等，需要注意一点的是一定要释放你申请的资源，这是个好习惯，更应该注意的一点是先创建的一定要后释放，因为后创建的可能是在先创建的环境下工作的。<br><br>到此为止，我们只是做好了最基础的准备工作，什么还都不能做呢<br>想做点什么吗？歇会吧，说点不得不说的题外话：<br><br>那么我们来看看颜色吧。有关色彩，分这么几种，256色（8位的），16位增强色，24位真彩和32位真彩。256色估计很少用了，16位目前还是主流，所以我们着重看一下16位增强色，通常16位增强色有两种格式：5.5.5和5.6.5，一般用RGB表示法表示。其中：<br>5.5.5格式，最高位为Alpha位，表示是不是透明，其余15位表示颜色，红绿蓝各5位，这种格式可以表示32786种颜色。通过宏<br><br><font color=#000000>＃define _RGB16BIT555(r,g,b)((b%32)+((g%32)&lt;&lt;5)+((r%32)&lt;&lt;10))来转变成5.5.5格式<br></font><br>对5.6.5格式，显然，红蓝各5位，绿6位，这样可以表示65536种颜色，同样，宏<br><br><font color=#000000>＃define _RGB16BIT565(r,g,b) ((b%32)+((g%64)&lt;&lt;6)+((r%32)&lt;&lt;11))来转变成5.6.5格式<br></font><br>中间的移位我也搞不清楚是怎么回事，姑且先不看了，看的越多可能越胡涂哦<br>那么到底该用哪种格式？看机器了，大部分可以用5.6.5，当然你可以检测一下，至于怎么检测嘛，我就不说了，查查相关资料就可以了。24位呢？红绿蓝各8位呗，32位？添个Alpha位，其余同24位。好了颜色就说到这里。<br><br>下面想干嘛？想在屏幕上搞点颜色出来，参看附的源代码code1<br>　　你会不会发现我们还应该在上面的基础上添点什么？对，应该在初始化函数里创建页面,也就是DirectDrawSurface对象，那它和DirectDraw对象什么区别？DirectDraw对象，我们知道是表示整个显示系统，也就是你的显卡和显屏构成的那个系统，你能在显示器屏幕上直接画点东西吗？不行，显屏上的东西是通过显存和内存操作把里面的东西显示出来，那么相对应于显屏，内存中就应该有一张矩形白纸供你作画，然后才能把它在显屏上显示。那张白纸就是DirectDrawSurface对象，代表了显存或内存里的一个连续的线性的数据区。这个数据区可以被代表显示硬件的DirectDraw对象所识别和确认。一般，可以创建的页面有4种，我们常用的有主页面（primary surface）和离屏页面（offscreen plain）先说主页面，就是一块显存，在主页面中的图形会显示到屏幕中，直接在主页面上操作会有个问题，数据一多，图象就会不连续，为此可以采用缓冲技术，即建立一个Back buffer（后台缓冲），说白了，就是在内存中再开辟一块区域，和主页面的区域对应，这样就可以不直接操作主页面，先把数据写入到这里，然后通过换页成为可见。离屏页面不同了，它是和主页面一模一样的画面，但是它永远不在屏幕上表现出来，通常被用来存储位图，用于将后来的位图图象Blit到主页面或后台缓冲上。那么，我们来看一下这几个页面在工作当中的位置及作用：<br><br>（此处有一图表，显示不出来）<br><br>这样，我们大体了解了页面的作用，那么初始化时就应该创建好，以等待到时对页面的操作。于是我们的初始化函数中就应该再添加：<br><br><font color=#000000>memset(&amp;ddsd,0,sizeof(ddsd));<br>ddsd.dwSize=sizeof(ddsd);<br>//设置dwFlags，告诉DirectDraw哪些成员可用<br>ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;<br>//定义ddsCaps.dwCaps，请求一个带后台缓冲的主页面<br>ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;<br>//定义设置后台缓冲的数量为1<br>ddsd.dwBackBufferCount = 1;<br>//创建主页面<br>if (FAILED(lpDDraw7-&gt;CreateSurface(&amp;ddsd, &amp;lpDDprimary, NULL)))<br>{<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>MessageBox(NULL,TEXT("DirectDraw Create primary Surface error!"),<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>TEXT("Wrong!"),MB_OK);<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>return(0);<br>}<br>//设置ddsCaps.dwCaps<br>ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;<br>//连接主页面及后台缓冲<br>if (FAILED(lpDDprimary-&gt;GetAttachedSurface(&amp;ddsd.ddsCaps, &amp;lpDDback)))<br>{<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>MessageBox(NULL,TEXT("DirectDraw Create back Surface error!"),<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>TEXT("Wrong!"),MB_OK);<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>return(0);<br>}</font><br><br>在这里，我们要定义几个全局变量：<br><font color=#000000>extern LPDIRECTSURFACE7 lpDDprimary;<br>extern LPDIRECTSURFACE7 lpDDback;<br>extern DDSURFACEDESC2 ddsd;</font><br><br>这是一个指向主页面的指针，一个指向后台缓冲的指针，和一个页面描述结构。不用说，这些定义你可以放在MyDirectDraw.h中。通过填充ddsd结构的成员来申明你所想创建的页面的类型。这里我们没创建离屏页面。用主页面及后台缓冲可以完成一些相对简单，数据不是很多的图形显示，数据过于复杂，就应该创建离屏页面了。<br><br>相应的，在结束时，除了释放DirectDraw7接口外，还要依次释放后台缓冲指针和主页面指针。还是提醒一下，先创建的一定要后释放，不然你会死的很难堪的。怎么去Release这些东西，看看code1中的代码，很容易明白的。<br><br>顺便我们看一下如何创建离屏页面，看下面代码：<br><font color=#000000>DDSURFACEDESC2 ddsd;<br>LPDIRECTSURFACE7 lpDDopl; //这两个定义不用说了吧<br>memset(&amp;ddsd,0,sizeof(ddsd)); //清空结构内容<br>ddsd.dwSize=sizeof(ddsd); //设置大小<br>ddsd.dwFlags = DDSD_CAPS |DDSD_HEIGHT|DDSD_WIDTH;<br>ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;//指定页面类型 <br>ddsd.dwWidth=600;<br>ddsd.dwHeight=800; //设置离屏页面大小<br>if (FAILED(lpDDraw7-&gt;CreateSurface(&amp;ddsd, &amp;lpDDopl, NULL)))<br>{<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>MessageBox(NULL,TEXT("DirectDraw Create offscreen plain error!"),<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>TEXT("Wrong!"),MB_OK);<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>return(0);<br>} //创建离屏页面</font><br><br>Okay！离屏页面就创建好了，说一下，因为离屏页面是个独立的页面，不隶属于任何其他页面，所以你必须指定它的大小。<br><br>关于页面的创建我们就说到这，到这儿，是不是有一种万事具备，只欠东风的感觉啊？<br><br>抬头一看，天亮了，该睡觉了，睡醒咱们再接着说，先去呼呼了。<br><br>&#8230;&#8230;n小时后&#8230;&#8230;<br><br>好了，既然只欠东风，我们就来说东风。<br><br>简单的画图，我们可以参看code1（在屏幕上打点）<br><br>　　有关页面的运用的位图的操作（作图也就这两个东西）我还组织不起来，无法把理解到的东西组织到程序中（汗！还没真正理解，就好意思在这说）我也在学嘛，多理解几遍，说不定就能够组织了，那么，那么，我们只能像我看过的几本资料一样，来拆开来说了，开始照单全收的抄书。希望抄完后，能有点组织的眉目。<br><br>　　从以前那个页面表，可以看出，这里的操作无非是载入位图，贴图，翻页显示，以及对画面进行剪贴。那我们一步步来说吧。这里就事论事，就模块论模块，代码段和以前的文件没多大关联了。大家看不明白了不要骂我，理解万岁。<br><br>先看载入位图，即将位图load到离屏页面中,要通过windows的HDC来进行存取，用windowsAPI配合DirectX来完成。我们看代码段：<br><br><font color=#000000>HDC hdc，hdc1； //声明HDC对象，hdc用来存储位图，hdc1代表离屏页面的DC<br>HBITMAP bitmap； //声明HBITMAP对象<br>hdc=::CreateCompatatibleDC(NULL)；//建立与目前显示模式兼容的DC（参数为null）<br>bitmap=(HBITMAP)::LoadImage(NULL,&#8221;bgroud.bmp&#8221;,IMAGE_BITMAP,640,480,LR_LOADFROMFILE);<br>//加载640*480的位图<br>::SelectObject(hdc,bitmap); //使用windows函数设置hdc中的内容为bitmap</font><br><br>现在把位图加载到了DC中，下面就要把DC中的位图贴到离屏页面中了<br><br><font color=#000000>LPDIRECTSURFACE7 lpDDopl; //这个定义不用说了吧<br>HRESULT result；//干嘛用的？往下看<br>lpDDopl-&gt;GetSurfaceDesc(&amp;ddsd);//ddsd和我们前面定义过的一样<br>result= lpDDopl-&gt;GetDC(&amp;hdc1);//用GetDC（）来取得离屏页面的DC<br>if(result!=DD_OK)<br><font face=Arial>&nbsp;&nbsp;&nbsp; </font>MessageBox(&#8220;取得暂存区DC失败&#8221;);//是否取得成功，了解result做这个用<br>：：Bitblt（hdc1，0，0，ddsd.dwWidth,ddsd.dwHeight,hdc,0,0,SRCCOPY）;<br>//这个就是贴图用的windows函数<br>lpDDopl-&gt;releaseDC(hdc1);//释放离屏页面的DC，一定要释放</font><br><br>到此我们已经把位图贴到离屏页面中了，下面应该把离屏页面DC中的位图填充到back buffer中，然后通过换页显示出来。先来了解两个DirectDraw的贴图函数Blt和BltFast。这两个函数的原型在老王翻译的directx开发手册中有详细说明，在我主页上可以down到，你可以查阅一下。这里我简单说一下：<br><br><font color=#000000>HRESULT Blt( LPRECT lpDestRect, //目标页面的区域，lpDestRect定义其左上右下点坐标<br>LPDIRECTDRAWSURFACE7 lpDDSrcSurface,//源页面指针<br>LPRECT lpSrcRect, //源页面的区域<br>DWORD dwFlags,//控制标志，详见老王的手册<br>LPDDBLTFX lpDDBltFx)//图形变换的信息结构，详情请自己查阅<br>HRESULT BltFast( DWORD dwX, //目的区域左上x坐标<br>DWORD dwY, //目的区域左上y坐标<br>LPDIRECTDRAWSURFACE7 lpDDSrcSurface，//源页面指针<br>LPRECT lpSrcRect, //源页面的区域<br>DWORD dwTrans，//转换参数，见老王手册</font><br><br>这两者的差别就是Blt多了图形放缩功能，但是BltFast效率较高，如何选用已经很清楚了。调用这两个函数中的一个就能够实现从离屏页面到back buffer的贴图，代码如下：<br><br><font color=#000000>lpDDback-&gt;BltFast(0,0,lpDDopl,CRect(0,0,640,480),DDBLTFAST_WAIT);</font><br><br>//lpDDback是我们以前声明过的后台缓冲，CRect（&#8230;）是个CRect类的对象，如果我们已声明了一个CRect rect；这里就可用&amp;rect来代替<br>单看贴图这步操作，还是很easy的。<br>看起来好像离显示只有一步之遥了啊，right，只要翻页（flip）一下就okay了<br><br>先看翻页函数：<br><font color=#000000>HRESULT Flip( LPDIRECTDRAWSURFACE7 lpDDDestSurface,//你想翻到的目标页<br>DWORD dwFlags) //通常设为DDFLIP_WAIT</font><br><br>说明一下：第一个参数为null时，表示翻到目前页面的所连接的下一个页面。当换页对象是可见的页面，比如主页面换页链，进行换页的Flip函数与系统CPU是异步执行的。这就是说，在这些可见的页面上，调用Flip函数，它只是简单的告诉显示硬件该进行换页了，并不需要等待换页操作在硬件设备中实际完成后才返回。这是因为显示硬件（显示器）只有在完成一次垂直刷新后才能进行一次换页。所以，Flip函数调用成功，并不意味着换页已经完成，在实际的换页操作进行之前，对即将成为主页面的后台缓存是不能锁定和进行Blit操作的。要让Flip函数成为与系统CPU同步的操作，在调用时指定DDFLIP_WAIT标志即可<br><br>代码同样简单：<br><font color=#000000>lpDDprimary-&gt;Flip（NULL,DDFLIP_WAIT）;</font><br><br>　　小功告成，到这儿我们已经把一个指定的位图bgroud.bmp在屏幕上显示出来了，这个就可以作为你的游戏的背景图，比如潜水艇游戏的那张大海图。<br><br>需要说明一下的是，如果我们要在哪个页面上操作（一般是back buffer），最好操作前先锁定，用完再解锁，防止其他GDI程序的干扰。举个例子:<br><font color=#000000>lpDDback-&gt;Lock(NULL,&amp;ddsd,DDLOCK-WAIT|DDLOCK_SURFACEMEMORYPTR, NULL); //锁定后台缓冲<br>lpDDback-&gt;Unlock(NULL);//解锁后台缓冲</font><br><br>把这两句代码分别添加到相应位置即可。<br><br>　　再往下我们该做什么了？背景有了，应该引进我们的精灵了（精灵这个术语真是可爱），然后想想看如何能让我们的精灵动起来。老实说，到这，我快崩溃了。下面的内容应该属于陌生的部分吧（如果前面的内容我还有点熟悉的话）。好在我这个人是很执着的，所以只有继续硬着头皮往下写了，理解不到位的地方还请大家包涵，同时希望大家指教。<br><br>先做做准备工作，去吃饭先，休息一会再来&#8230;&#8230;&#8230;&#8230;<br><br>&#8230;&#8230;又是n个小时&#8230;&#8230;<br><br>有饭吃的日子真爽啊，珍惜吧，朋友们：）深吸一口气，let&#8217;s go on<br><br>运用DirectDraw来做动画，我们把不同的图片载入到离屏页面中，然后定时贴入到back buffer中，翻页显示就出现动画效果了。来看个例程：<br><br><strong>（待续） From：<a href="http://blog.gameres.com/show.asp?blogID=269&amp;column=0"><u><font color=#800080>活着为了游戏 — GameRes Blog</font></u></a></strong></font></td>
        </tr>
        </font>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86488.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:43 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86488.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DirectX 5.0 最新游戏编程指南</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86487.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:41:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86487.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86487.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86487.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86487.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86487.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DirectX5T.htm">http://dev.gameres.com/Program/Visual/2D/DirectX5T.htm</a><br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <p align=center><font face=Tahoma color=#ffffcc><strong>DirectX 5.0 最新游戏编程指南</strong></font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">　
                        <div align=center>
                        <center>
                        <table cellSpacing=0 cellPadding=0 width="95%" border=0>
                            <tbody>
                                <tr>
                                    <td width="100%"><font face=Tahoma size=2>DirectX是为Visual C++的用户准备的，因此要编制DirectDraw游戏程序，最好对VC要有一定的了解。不愿意使用VC的用户也可以利用Arakelian Soft公司开发的专门针对Visual Basic5.0用户的ActiveX控件DirectStudio98或Tegosoft公司的TegoSoft ActiveX for Visual Basic。不过，如果想充分发挥DirectX的性能，并且希望保持程序的兼容，那么最好还是使用Visual C++。<br>为了叙述方便，假定已经安装了DirectX5.0 SDK 和Visual C++ 5.0，其目录分别是C:\DX5SDK和C:\Program Files\DevStudio。如果你使用了另一种编译器或安装到了其它目录下，必须将下面的例子做适当的修改才能运行。有人安装了DirectX SDK后却不知怎样使用，因为它是基于Visual C++的，却没有一个界面友好的集成开发环境，因此必须对Visual C++进行适当的配制。<br><br><strong>一 配置DirectX SDK</strong><br>1.1 配置Microsoft Developer Studio<br>为了编译DirectX SDK提供的例子，需要打开一个新的project workspace，插入适当的文件，设置环境变量使得编译器能够找到需要的链接库和包含文件，下面描述了设置的全部过程。启动Microsoft Developer Studio，安装下述步骤创建工程：<br>.在File菜单，选择New；<br>.在New对话框中选择Project中的Win32 Application，在Project Name输入DDEX1<br>.在Location文本框输入放置工程文件的位置，点OK按钮<br>.一个新的DDEX1 Classes文件夹就出现在workspace窗口的左边了。<br>创建了工程后，需要使用如下步骤向工程插入适当的文件：<br>.在Project菜单选择Add toProject|Files<br>.浏览到C:\DX5SDK\SDK\SAMPLES\DDEX1 目录，选择所有的文件<br>.选择OK，该目录下的DDEX1.CPP、DDEX1.RC、RESOURCE.H就加入到工程了。<br>然后设置包含文件的路径：<br>.在Tools菜单，选择Options，就弹出Options对话框<br>.选择Directories ，在Show Directories For列表框选择Include files<br>.在Directories:列表框双击列表底部的空白行，输入C:\DX5SDK\SDK\INC.<br>.同样再加入另一个路径C:\DX5SDK\SDK\SAMPLES\MISC<br>.选择OK按钮，<br>设置链接库目录：<br>.在Show Directories For列表框选择Library files<br>.在Directories:列表框双击底部空白行，输入C:\DX5SDK\SDK\LIB.<br>.单击OK按钮。<br>最后设置建立应用程序时链接的模块：<br>.在Project菜单单击Settings.<br>.选择Link<br>.在Category下拉框选择General.<br>.在Object/Library模块列表框加入Ddraw.lib和Winmm.lib.<br>.单击OK.<br>1.2 配制NMAKE路径<br>　　有时候命令行的方式比集成环境更加方便，所以许多有经验的程序员更愿意用命令行的方式来建立应用程序。下面是包含文件和链接库模块的路径：<br>@echo off<br>set PATH=C:\Program Files\DevStudio\SharedIDE\Bin;<br>C:\Program Files\DevStudio\Vc\Bin;%PATH%set INCLUDE=C:\Program Files\DevStudio\Vc\include;<br>C:\Program Files\DevStudio\Vc\Mfc\include;C:\DX5SDK\SDK\INC;%INCLUDE%set LIB= C:\Program Files\DevStudio\SharedIDE\Vc\lib;<br>C:\Program Files\DevStudio\Vc\Mfc\lib; C:\DX5SDK\SDK\LIB;%LIB%set INIT= C:\Program Files\DevStudio;%INIT%将上述内容加入Autoexec.bat。在例子的目录下输入<br>NMAKE<br>将会在当前目录下创建一个DEBUG目录，并将生成的可执行文件放在该目录下。<br>为了在学习的过程中熟悉DirectX SDK，我们将按照DirectX SDK提供的范例程序的顺序由浅入深，循序渐进。<br>1.3 为Borland C++5.0配置DirectX SDK<br>尽管DirectX 5 SDK是主要为Visual C++用户准备的，但Microsoft并未忘记众多的BorlandC++用户，所以在DirectX SDK中也提供了DirectX的Borland C++库。不过，可能出于竞争的缘故（猜测而已），安装后的DirectX SDK中并没有Borland C++库。这就需要用户自己来处理这一恼人的问题了。我们知道，DirectX 5 SDK是以一个IDX5SDK.EXE发布的，运行IDX5SDK后，它先将压缩的文件全部解压到某个目录下（如D:\DX5SDK），然后再运行该目录下的SETUP.EXE安装DirectX SDK（假设目录为C:\DX5SDK）。实际上，在解压后的目录中包含了一个D:\DX5SDK\SDK\LIB\BORLANDC目录，该目录下就是Borland C++的链接库文件。但在SETUP安装时，安装程序并没有把该目录复制到安装目录中。解决方法很简单，即SETUP安装完成后，再建立一个C:\DX5SDK\SDK\LIB\Borland，将目录D:\DX5SDK\SDK\LIB\Borland下的所有文件都复制到C:\DX5SDK\SDK\LIB\Borland目录下。然后在Borland C++5.0的集成环境中如同配置Visual C++5.0那样配置工程文件。<br><br><strong>二 第一个DirectDraw实例</strong><br>要使用DirectDraw，首先必须创建DirectDraw对象的一个实例来表征计算机上的显示适配卡，然后使用接口方法来处理对象。另外还需要创建一个或多个DirectDrawSurface对象的实例来显示游戏。DDEX1首先创建一个DirectDraw对象，再创建一个主表面（primary<br>surface）和一个后台缓冲区（back buffer），然后在表面之间转换。DDEXx例子都是用C++写成的，如果你使用的是C编译器，必须将代码做适当改动，至少要加入虚表和指向接口方法的指针。<br>2.1 首先初始化DirectDraw对象<br>DDEX1 程序在doInit函数包含了DirectDraw 的初始化代码：<br><br></font><font face=宋体 color=#99ccff size=2>// 创建主DirectDraw 对象<br>ddrval = DirectDrawCreate( NULL, &amp;lpDD, NULL );<br>if( ddrval == DD_OK )<br>{<br>&nbsp;&nbsp;&nbsp; // 获取独占模式<br>&nbsp;&nbsp;&nbsp; ddrval = lpDD-&gt;SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE| DDSCL_FULLSCREEN );<br>&nbsp;&nbsp;&nbsp; if(ddrval == DD_OK )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddrval = lpDD-&gt;SetDisplayMode(640, 480, 8 );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ddrval == DD_OK )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //创建带有一个后台缓冲区的主表面<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddsd.dwSize = sizeof( ddsd );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |DDSCAPS_FLIP |DDSCAPS_COMPLEX;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddsd.dwBackBufferCount = 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddrval = lpDD-&gt;CreateSurface( &amp;ddsd, &amp;lpDDSPrimary, NULL );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ddrval == DD_OK )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //获取后台缓冲区的指针<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddscaps.dwCaps = DDSCAPS_BACKBUFFER;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddrval=lpDDSPrimary-&gt;GetAttachedSurface(&amp;ddscaps,&amp;lpDDSBack);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ddrval == DD_OK )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 画出一些文本<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lpDDSPrimary-&gt;GetDC(&amp;hdc) == DD_OK)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetBkColor( hdc, RGB( 0, 0, 255 ) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetTextColor( hdc, RGB( 255, 255, 0 ) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDDSPrimary-&gt;ReleaseDC(hdc);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (lpDDSBack-&gt;GetDC(&amp;hdc) == DD_OK)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetBkColor( hdc, RGB( 0, 0, 255 ) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetTextColor( hdc, RGB( 255, 255, 0 ) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDDSBack-&gt;ReleaseDC(hdc);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 创建翻转页面的计时器if( SetTimer( hwnd, TIMER_ID, TIMER_RATE, NULL ) )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br>wsprintf(buf, "Direct Draw Init Failed (%08lx)\n", ddrval );<br>............</font><font face=Tahoma size=2><br><br>下面详细说明初始化DirectDraw 对象的创建和准备表面的每一步骤。<br><br>2.2 创建DirectDraw 对象<br>创建DirectDraw 对象的一个实例，应该用DirectDrawCreate API 函数，也可以用COM中的CoCreateInstance函数。DirectDrawCreate用一个全局统一标志符GUID(Globally<br>Unique IDentifier)来表征显示设备，在大多数情况下GUID为NULL(使用系统的缺省显示设备，既&#8220;空设备&#8221;）；指针指向DirectDraw对象的地址；第三个参数总是NULL(供将来扩展使用)。下述代码表明了如何创建一个DirectDraw对象，并且检验是否成功。<br><br></font><font face=宋体 color=#99ccff size=2>ddrval = DirectDrawCreate( NULL, &amp;lpDD, NULL );<br>if( ddrval == DD_OK )<br>{<br>&nbsp;&nbsp;&nbsp; // lpDD is是合法的DirectDraw 对象<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; // DirectDraw对象不能被创建<br>}</font><font face=Tahoma size=2><br><br>2.3 设置显示模式<br>设置DirectDraw 应用程序的显示模式需要两步：首先调用IDirectDraw::SetCooperativeLevel方法来设定该模式下的要求，一旦确定了要求，再用IDirectDraw::SetDisplayMode方法来选择显示分辨率。<br>在改变显示分辨率之前，还必须通过IDirectDraw::SetCooperativeLevel方法来指定DDSCL_EXCLUSIVE和DDSCL_FULLSCREEN标志。<br>　　这样能使游戏程序完全控制显示设备，其它的应用程序不能同时共享显示设备。DDSCL_FULLSCREEN标志表示将程序设为全屏模式。下面的代码显示了如何使用IDirectDraw::SetCooperativeLevel方法：<br><br></font><font face=宋体 color=#99ccff size=2>HRESULT ddrval;<br>LPDIRECTDRAW lpDD; // already created by DirectDrawCreate<br>ddrval = lpDD-&gt;SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);<br>if( ddrval == DD_OK )<br>{<br>&nbsp;&nbsp;&nbsp; // 全屏独占方式设置成功<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; // 调用不成功，但程序仍然能继续运行<br>}<br></font><font face=Tahoma size=2><br>如果IDirectDraw::SetCooperativeLevel不返回DD_OK，你仍然可以运行该程序，但不是全屏模式，有时可能产生一些无法预料的错误。因此你应该显示一条错误信息，让用户知道发生了什么事，由用户来决定是否继续运行游戏。<br>使用IDirectDraw::SetCooperativeLevel时，必须向窗口 (HWND)传送一个句柄，让窗口决定何时非正常地终止应用程序。例如，若发生了GP错误或GDI被翻转(flip)到了后台缓冲区，用户就无法访问当前屏幕。为了避免这种情况，DirectDraw有一个后台等待进程，它俘获所有发往该窗口的消息，用这些消息来确定应用程序何时终止。如果创建了新的窗口，必须确定该窗口为活动的，否则，就会有一系列的事件无法继续工作。<br><br>2.4 改变显示模式<br>一旦选择了应用程序的工作模式，就可以使用IDirectDraw::SetDisplayMode方法来改变显示模式，下面的代码将显示模式设置成640x480x256：<br><br></font><font face=宋体 color=#99ccff size=2>HRESULT ddrval;<br>LPDIRECTDRAW lpDD; // already created<br>ddrval = lpDD-&gt;SetDisplayMode( 640, 480, 8 );<br>if( ddrval == DD_OK )&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; // 改变模式成功<br>}<br>else&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; // 显示模式不能改变 // 系统可能不支持该模式<br>}</font><font face=Tahoma size=2><br><br>当设定显示模式时，应该确保如果用户的设备不支持更高的分辨率，应用程序应该返回系统支持的标准模式。如果显示示配卡不支持设计的分辨率，IDirectDraw::SetDisplayMode返回一个DDERR_INVALIDMODE错误值。因此，在设置分辨率时，应该先用IDirectDraw::EnumDisplayMode方法检测用户的显示设备的性能。<br><br>2.5 创建可翻转表面(Flippable Surface)<br>设定了显示模式后，必须创建放置应用程序的表面。在DDEX1例中，我们使用IDirectDraw::SetCooperativeLevel方法将程序设成独占全屏模式，然后可以创建翻转表面。如果使用IDirectDraw::SetCooperativeLevel设成DDSCL_NORMAL模式，就只能创建块写方式的表面了。<br><br>2.6 定义表面要求<br>创建可翻转表面的的第一步是在DDSURFACEDESC结构中定义表面的要求。下面的代码描述了结构的定义及创建可翻转表面所需要的标志：<br><br></font><font face=宋体 color=#99ccff size=2>// 创建带有一个后台缓冲区的主表面<br>ddsd.dwSize = sizeof( ddsd );<br>ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;<br>ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |DDSCAPS_COMPLEX;<br>ddsd.dwBackBufferCount = 1;</font><font face=Tahoma size=2><br><br>例中，成员变量dwSize被设为DDSURFACEDESC结构的大小。dwFlags标志指定DDSURFACEDESC结构中哪些域可存放有效信息。<br>在DDEX1例中，dwFlags指出了需要使用DDSCAPS结构(DDSD_CAPS)并创建一个后台缓冲区<br>(DDSD_BACKBUFFERCOUNT)。dwCaps指出 DDSCAPS结构会用到的标志，本例中它指定了一个主表面(DDSCAPS_PRIMARYSURFACE)，一个翻转表面(DDSCAPS_FLIP)和一个复杂表面(DDSCAPS_COMPLEX)。<br>　　最后，程序指定了一个后台缓冲区。后台缓冲区是背景图像和人物将写入的位置，它可以转化为主表面。<br>本例中，后台缓冲区的数目为1，事实上，只要有足够的显示内存，可以创建任意多个后台缓冲区，一般每1M的显示内存只能用来创建一个后台缓冲区。表面的内存既可以是显示内存，也可以是系统内存。<br>DirectDraw在使用完了显示内存时（例如在仅有1M的显示内存创建了2个后台缓冲区）会自动使用系统内存。你可以通过将DDSCAPS结构中的dwCaps设定为DDSCAPS_SYSTEMMEMORY或DDSCAPS_VIDEOMEMORY来指定只使用系统内存或只使用显示内存。如果指定了DDSCAPS_VIDEOMEMORY又没有足够的显示内存来创建表面，IDirectDraw::CreateSurface<br>将返回一个DDERR_OUTOFVIDEOMEMORY错误。<br><br>2.7 创建表面<br>填完了DDSURFACEDESC结构，就可以使用该结构和lpDD了，lpDD是用DirectDrawCreate<br>方法创建的DirectDraw 对象的指针，下面的代码显示了这一过程：<br><br></font><font face=宋体 color=#99ccff size=2>ddrval = lpDD-&gt;CreateSurface( &amp;ddsd, &amp;lpDDSPrimary, NULL);<br>if( ddrval == DD_OK )&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; // lpDDSPrimary points to new surface<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; // surface was not created return FALSE;<br>}</font><font face=Tahoma size=2><br><br>如果调用成功，IDirectDraw::CreateSurface函数就返回指向主表面的指针lpDDSPrimary。若主表面指针可用，就可以调用IDirectDrawSurface::GetAttachedSurface 方法取得后台缓冲区的指针，如下所示：<br><br></font><font face=宋体 color=#99ccff size=2>ddscaps.dwCaps = DDSCAPS_BACKBUFFER;ddrval = lpDDSPrimary-&gt;GetAttachedSurface( &amp;ddcaps, &amp;lpDDSBack);<br>if( ddrval == DD_OK )&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; // lpDDSBack points to the back buffer<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; return FALSE;<br>} </font><font face=Tahoma size=2><br><br>如果IDirectDrawSurface::GetAttachedSurface调用成功，通过提供主表面的地址和设置DDSCAPS_BACKBUFFER标志，lpDDSBack 参数就指向后台缓冲区。<br><br>2.8 着色表面<br>创建了主表面和后台缓冲区后，DDEX1使用标准的WindowsGDI 函数将一些文本提交到主表面和后台缓冲区，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>if (lpDDSPrimary-&gt;GetDC(&amp;hdc) == DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; SetBkColor( hdc, RGB( 0, 0, 255 ) );<br>&nbsp;&nbsp;&nbsp; SetTextColor( hdc, RGB( 255, 255, 0 ) );<br>&nbsp;&nbsp;&nbsp; TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg));<br>&nbsp;&nbsp;&nbsp; lpDDSPrimary-&gt;ReleaseDC(hdc);<br>}<br>if (lpDDSBack-&gt;GetDC(&amp;hdc) == DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; SetBkColor( hdc, RGB( 0, 0, 255 ) );<br>&nbsp;&nbsp;&nbsp; SetTextColor( hdc, RGB( 255, 255, 0 ) );<br>&nbsp;&nbsp;&nbsp; TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg));<br>&nbsp;&nbsp;&nbsp; lpDDSBack-&gt;ReleaseDC(hdc);<br>}</font><font face=Tahoma size=2><br><br>例中使用了IDirectDrawSurface::GetDC方法来设备上下文的句柄且锁定该表面。如果不想使用要求句柄的Windows函数，还可以使用IDirectDrawSurface::Lock和IDirectDrawSurface::Unlock方法来锁定和解锁后台缓冲区。锁定表面的内存（不管是整个表面还是其中的一部分）能确保你的应用程序和系统不会同时访问这块内存。另外，除非给内存解锁，程序不能翻转表面。本例在锁定表面后使用Windows GDI 函数SetBkColor来设置背景颜色，使用SetTextColor来设置文本颜色，然后使用TextOut将文本输出到表面。当文本写入缓冲区后，例中使用了IDirectDrawSurface::ReleaseDC方法来解锁表面并释放句柄。良好的习惯是，向后台缓冲区写数据完成后，马上调用IDirectDrawSurface::ReleaseDC或IDirectDrawSurface::Unlock。<br>一般来讲，当向表面写数据时，该表面就是后台缓冲区，然后将缓冲区翻转成主表面显示出来。在DDEX1中，第一次翻转表面之前有一个重要的延迟。于是DDEX1就将数据写入主缓冲区，避免开始显示时有太长的时间间隔。后面将会讲到，DDEX1只在WM_TIMER期间向后台写数据。初始化函数或标题头可能会写入主缓冲区。应该注意的是，一旦使用IDirectDrawSurface::Unlock对表面解锁，指向表面的指针就变成无效，必须再次使用IDirectDrawSurface::Lock方法才能获取该表面内存的有效指针。<br><br>2.9 写表面及翻转表面<br>完成了初始化后，DDEX1开始处理消息循环。在消息循环的过程中，完成锁定后台缓冲区——写入新的文本——解锁后台缓冲区——翻转表面的过程。WM_TIMER包含了写数据和翻转表面的大部分代码。<br>WM_TIMER消息的前半部分用于向后台缓冲区写数据，&#8220;phase&#8221;变量决定是写主缓冲区消息还是写后台缓冲区消息。如果phase为1，表示写主缓冲区的消息，然后将phase改变为0；若为0，表示写后台缓冲区的消息，然后将phase改变为1。注意，两种情况中的消息都是写向后台缓冲区。后台缓冲区写入了消息后，使用IDirectDrawSurface::ReleaseDC方法解锁。下面的代码实现了这一点：<br><br></font><font face=宋体 color=#99ccff size=2>case WM_TIMER:<br>// Flip surfaces<br>if( bActive )&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; if (lpDDSBack-&gt;GetDC(&amp;hdc)== DD_OK)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetBkColor( hdc, RGB( 0, 0, 255 ) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetTextColor( hdc, RGB( 255, 255, 0 ) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( phase )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phase = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg) );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phase = 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDDSBack-&gt;ReleaseDC(hdc);<br>&nbsp;&nbsp;&nbsp; }</font><font face=Tahoma size=2><br><br>表面内存解锁后，使用IDirectDrawSurface::Flip方法将后台缓冲区翻转成主表面，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>while( 1 )&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; HRESULT ddrval;<br>&nbsp;&nbsp;&nbsp; ddrval = lpDDSPrimary-&gt;Flip( NULL, 0 );<br>&nbsp;&nbsp;&nbsp; if( ddrval == DD_OK )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if( ddrval == DDERR_SURFACELOST )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(ddrval = lpDDSPrimary-&amp;g&gt;val != DD_OK )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if( ddrval != DDERR_WASSTILLDRAWING )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; }<br>}</font><font face=Tahoma size=2><br><br>例中，lpDDSPrimary指明了主表面及其后台缓冲区。调用IDirectDrawSurface::Flip方法后，主表面和后表面交换。调用成功后，返回DD_OK，程序终止While循环；如果返回DDERR_SURFACELOST，表明可能是表面丢失，需要用IDirectDrawSurface::Restore方法恢复该表面，若恢复成功，就再一次调用IDirectDrawSurface::Flip方法；如果失败，程序终止While循环并返回一个错误值。另外，如前所述，即使调用IDirectDrawSurface::Flip成功，交换也不是立即完成，它将等到系统中在此之前的表面交换都完成后才进行。例如，前一次的表面翻转还未发生时，IDirectDrawSurface::Flip就返回DERR_WASSTILLDRAWING。本例中，IDirectDrawSurface::Flip继续循环直到返回DD_OK.。<br><br>2.10 释放DirectDraw 对象<br>当按了F12后，DDEX1程序在退出之前先处理WM_DESTROY消息，该消息调用了finiObjects函数，而finiObjects函数包含了所有的Iunknown Release的调用，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>static void finiObjects( void )<br>{<br>&nbsp;&nbsp;&nbsp; if( lpDD != NULL )&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( lpDDSPrimary != NULL)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDDSPrimary-&gt;Release();lpDDSPrimary = NULL; } lpDD-&gt;Release();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDD = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>} /* finiObjects */</font><font face=Tahoma size=2><br><br>程序检测DirectDraw对象的指针(lpDD)和DirectDrawSurface对象的指针(lpDDSPrimary)<br>是否等于NULL，本例中显然不为NULL。然后DDEX1调用 IDirectDrawSurface::Release方法将DirectDrawSurface对象的参考值减1，这将会使得其参考值变为0，DirectDrawSurface 对象就被释放了，DirectDrawSurface的指针被设为NULL值，然后撤消。程序又调用IDirectDraw::Release就DirectDraw对象的参考值减1变为0，释放DirectDraw对象及其指针。<br>上述的DDEX1是DirectDraw最基本的应用，它首先创建DirectDraw对象和DirectDrawSurface对象，创建一个主表面及其后台缓冲区，将文本输出到后台缓冲区，然后转化表面。第二个例子DDEX2扩展了DDEX1的功能，它可以将一个位图文件调入后台缓冲区。第三个例子DDEX3则更进一步，除了一个主表面及后台缓冲区外，还创建了两个屏外表面，将位图调入每一个屏外表面，然后使用IDirectDrawSurface::BltFast方法将一个屏外表面的内容位块传输到后台缓冲区，然后翻转表面并将另一个屏外表面的内容位块传输到后台缓冲区。下面将详细讨论这些功能。<br><br>2.11 将位图调入表面<br>如DDEX1中一样，doInit函数是DDEX2的初始化函数，两者的实质一样，一直到下面的代码：<br><br></font><font face=宋体 color=#99ccff size=2>lpDDPal = DDLoadPalette(lpDD, szBackground);<br>if (lpDDPal == NULL)<br>&nbsp;&nbsp;&nbsp; goto error;<br>ddrval = lpDDSPrimary-&gt;SetPalette(lpDDPal);<br>if( ddrval != DD_OK )<br>&nbsp;&nbsp;&nbsp; goto error;<br>// load a bitmap into the back buffer.<br>ddrval = DDReLoadBitmap(lpDDSBack, szBackground);<br>if( ddrval != DD_OK )<br>&nbsp;&nbsp;&nbsp; goto error;</font><font face=Tahoma size=2><br><br>代码的第一行从函数DDLoadPalette返回一个值，该函数在C:\DX5SDK\SDK\SAMPLES\MISC中的Ddutil.cpp文件中，因此编译DDEX2时需要将Ddutil.cpp和Ddutil.h加入过程。大部分的DirectDraw程序都需要该文件。在DDEX2中，DDLoadPalette函数从Back.bmp文件中创建一个DirectDrawPalette对象。DDLoadPalette函数首先检查用于创建调色板的文件或资源十分存在，如果不存在，就创建一个缺省调色板。在DDEX2中，它从位图文件中抽取调色板信息并存储在由ape指向的结构，然后如下创建DirectDrawPalette对象：<br><br></font><font face=宋体 color=#99ccff size=2>pdd-&gt;CreatePalette(DDPCAPS_8BIT, ape, &amp;ddpal, NULL);<br>return ddpal;</font><font face=Tahoma size=2><br><br>当IDirectDraw::CreatePalette方法返回时，ddpal就指向该DirectDrawPalette对象。ape是指向一个结构的指针，该结构能包含2/4/16/256个线性的实体，实体的数目由IDirectDraw::CreatePalette调用的dwFlags参数决定。本例中，dwFlags设定为DDPCAPS_8BIT，这表示该结构中有256个实体，每个实体有四个字节（红色、绿色、蓝色和标志字节）。<br><br>2.12 设置调色板，将位图调入后台缓冲区<br>创建了调色板之后，可以通过调用IDirectDrawSurface::SetPalette方法将DirectDrawPalette 对象的指针ddpal传送给主表面，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>ddrval = lpDDSPrimary-&gt;SetPalette(lpDDPal);<br>if( ddrval != DD_OK )<br>&nbsp;&nbsp;&nbsp; // SetPalette failed</font><font face=Tahoma size=2><br><br>调用了IDirectDrawSurface::SetPalette方法之后，DirectDrawPalette对象就和DirectDrawSurface对象挂(hook)在一起了，需要改变调色板时，只需要创建一个新的调色板对其进行设置就可以了。<br>　　DirectDrawPalette对象同DirectDrawSurface对象挂在一起后，DDEX2使用以下代码将Back.bmp文件装入后台缓冲区：<br><br></font><font face=宋体 color=#99ccff size=2>// load a bitmap into the back buffer.<br>ddrval = DDReLoadBitmap(lpDDSBack, szBackground);<br>if( ddrval != DD_OK )<br>&nbsp;&nbsp;&nbsp; // Load failed</font><font face=Tahoma size=2><br><br>DDReLoadBitmap是Ddutil.cpp中的另一个函数，它将位图从文件或资源中调入已经存在的DirectDraw表面。在本例中，它将szBackground指向的Back.bmp装入lpDDSBack指向的后台缓冲区。DDReLoadBitmap调用DDCopyBitmap函数将文件拷贝到后台缓冲区并延展为适当的尺寸。DDCopyBitmap函数将位图拷入内存，使用GetObject函数获取位图的大小，然后用下述代码获取将要放置位图的后台缓冲区的大小：<br><br></font><font face=宋体 color=#99ccff size=2>// get size of surface.<br>ddsd.dwSize = sizeof(ddsd);<br>ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;<br>pdds-&gt;GetSurfaceDesc(&amp;ddsd);</font><font face=Tahoma size=2><br><br>　　ddsd 是指向DDSURFACEDESC结构的指针，该结构储存了DirectDraw表面的当前描述。DDSURFACEDESC结构的成员描述了由DDSD_HEIGHT 和DDSD_WIDTH指定了表面的高和宽。IDirectDrawSurface::GetSurfaceDesc方法使用合适的值调入结构，例中高为480，宽为640。DDCopyBitmap函数锁定表面并将位图拷贝到后台缓冲区，然后用StretchBlt函数对位图进行拉伸或压缩，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>if ((hr = pdds-&gt;GetDC(&amp;hdc)) == DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; StretchBlt(hdc, 0, 0, ddsd.dwWidth,ddsd.dwHeight, hdcImage, x, y, dx, dy, SRCCOPY);<br>&nbsp;&nbsp;&nbsp; pdds-&gt;ReleaseDC(hdc);<br>}</font><font face=Tahoma size=2><br><br>2.13 从屏外表面位块传输<br>DDEX2同DDEX1基本相同。DDEX2打开一个位图文件并将它送往后台缓冲区，然后翻转后台缓冲区和主表面。但这对显示位图并不特别理想，DDEX3扩展了DDEX2的功能，它加入了两个屏外缓冲区，每个缓冲区都存储一个位图。下面是DDEX3中的doInit函数的一部分，功能是创建两个屏外缓冲区：<br><br></font><font face=宋体 color=#99ccff size=2>// Create an offscreen bitmap.<br>ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;<br>ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;<br>ddsd.dwHeight = 480;<br>ddsd.dwWidth = 640;<br>ddrval = lpDD-&gt;CreateSurface( &amp;ddsd, &amp;lpDDSOne, NULL);<br>if( ddrval != DD_OK )<br>{<br>&nbsp;&nbsp;&nbsp; return initFail(hwnd);<br>}<br>// Create another offscreen bitmap. ddrval = lpDD-&gt;CreateSurface( &amp;ddsd, &amp;lpDDSTwo, NULL); if( ddrval != DD_OK )<br>{<br>&nbsp;&nbsp;&nbsp; return initFail(hwnd);<br>} </font><font face=Tahoma size=2><br><br>从代码中可以看到，dwFlags指明了程序使用DDSCAPS结构，并设置缓冲区的高和宽。由DDSCAPS结构中的DDSCAPS_OFFSCREEN标志指定该表面是屏外缓冲区，在DDSURFACEDESC结构中将高和宽设为480和640，然后使用IDirectDraw::CreateSurface方法来创建表面。因为两个屏外表面的大小一样，创建第二个缓冲区只需要再运行一次IDirectDraw::CreateSurface即可（当然要用不同的指针）。你还可以在DDSCAPS中设置DDSCAPS_SYSTEMMEMORY或DDSCAPS_VIDEOMEMORY 来指定屏外缓冲区放在显示内存还是系统内存。将位图存放在显示内存可以加快后台缓冲区与屏外表面之间的数据传输速度，这在位图动画中非常重要。但是，如果你为屏外缓冲区指定了DDSCAPS_VIDEOMEMORY又没有足够的显示内存调入整个位图，当创建该表面时，程序就会返回一个DDERR_OUTOFVIDEOMEMORY的错误值。<br><br>2.14 将位图文件调入屏外表面<br>创建了两个屏外表面后，DDEX3使用了InitSurfaces函数将位图从Frntback.bmp文件装入到两个表面。InitSurfaces函数使用了DDCopyBitmap函数调入两个位图，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>// Load our bitmap resource.<br>hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);<br>if (hbm == NULL)<br>&nbsp;&nbsp;&nbsp; return FALSE;<br>DDCopyBitmap(lpDDSOne, hbm, 0, 0, 640, 480);<br>DDCopyBitmap(lpDDSTwo, hbm, 0, 480, 640, 480);<br>DeleteObject(hbm);<br>return TRUE;</font><font face=Tahoma size=2><br><br>Frntback.bmp文件由两部分组成，一半在上，一半在下。DDCopyBitmap函数将上半部分调入第一个屏外表面lpDDSOne，下半部分调入第二个表面lpDDSTwo。<br><br>2.15 将屏外表面位位块传输到后台缓冲区<br>WM_TIMER包含了写表面和翻转表面的代码。在DDEX3中，它选择适当的屏外表面，并将其位块传输到后台缓冲区，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>rcRect.left = 0;<br>rcRect.top = 0;<br>rcRect.right = 640;<br>rcRect.bottom = 480;<br>if(phase)<br>{<br>&nbsp;&nbsp;&nbsp; pdds = lpDDSTwo;<br>&nbsp;&nbsp;&nbsp; phase = 0;<br>}<br>else {<br>&nbsp;&nbsp;&nbsp; pdds = lpDDSOne;<br>&nbsp;&nbsp;&nbsp; phase = 1;<br>}<br><br>while( 1 )<br>{<br>&nbsp;&nbsp;&nbsp; ddrval = lpDDSBack-&gt;BltFast(0, 0, pdds, &amp;rcRect, FALSE );<br>&nbsp;&nbsp;&nbsp; if( ddrval ==DD_OK )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>}</font><font face=Tahoma size=2><br><br>&#8220;phase&#8221;决定了准备将哪一个屏外表面位块传输到后台缓冲区，然后调用IDirectDrawSurface::BltFast方法将选定的屏外表面位块传输到后台缓冲区，从左上角的位置0,0开始。rcRect指向定义了屏外表面的左上角和右下角的RECT结构。最后一个参数设为FALSE或0，指明不使用特殊的传输标志。一旦屏外表面被传送到后台缓冲区，就可以利用前面的方法将后台缓冲区和主表面相互翻转了。<br><br><strong>三、创建动画</strong><br>上面的例子都只是将数据写入后台缓冲区，然后将后台缓冲区与主表面翻转，其速度并不太快。下面的例子DDEX4和DDEX5优化了实时功能，使看起来更象一个真正的游戏。DDEX4显示了怎样为表面设置Color key，怎样使用IDirectDrawSurface::BltFast方法将屏外表面各部分拷贝到后台缓冲区以产生动画。DDEX5加入了读取调色板并在动画运行时改变调色板的功能。<br><br>3.1 Color Key和位图动画<br>在DDEX3例中描述了将位图放入屏外缓冲区的一种主要方式。DDEX4则使用了将背景和一系列的精灵(sprite，本例中精灵是圆环)装入屏外表面的技术，然后使用,IDirectDrawSurface::BltFast方法将屏外表面的各部分拷贝到后台缓冲区。doInit函数除了具有前面例子中的功能外，还包括了为精灵设置Color key的代码。Color key是用于设置透明度的颜色值。当使用硬件块写方式时，矩型区域内除了设为color key的像素，其它的像素都被块写，由此在表面上产生非矩型的精灵。设置color key的代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>// Set the color key for this bitmap (black)<br>// NOTE this bitmap has black as entry 255 in the color table.<br>// ddck.dwColorSpaceLowValue = 0xff;<br>// ddck.dwColorSpaceHighValue = 0xff;<br>// lpDDSOne-&gt;SetColorKey( DDCKEY_SRCBLT, &amp;ddck);<br>// if we did not want to hard code the palette index (0xff)<br>// we can also set the color key like so...<br>DDSetColorKey(lpDDSOne, RGB(0,0,0));<br>return TRUE;</font><font face=Tahoma size=2><br><br>例中给出了设置color key的两种不同方法。第一种方法是注释内的3行，先设定DDCOLORKEY<br>结构中color key的范围，再调用IDirectDrawSurface::SetColorKey方法将color key 设置成黑色（假定位图在颜色表中以黑色作为调色板索引项255）。第二种方法是调用DDSetColorKey函数设置颜色的RGB值来选择color key，黑色就是RGB(0,0,0)。DDSetColorKey 函数调用了DDColorMatch函数，DDColorMatch存储放置于lpDDSOne表面的位图的0,0位置像素的颜色值，然后用提供的RGB值赋给0,0位置的像素，并将该颜色值屏蔽。<br>　　完成了这一步骤后，原来的颜色就可重新放回0,0处并用正确的Color Key调用DDSetColorKey函数，调用成功后，color key就放入DDCOLORKEY 结构中的成员变量dwColorSpaceLowValue ，同时也拷贝到dwColorSpaceHighValue成员，然后再调用IDirectDrawSurface::SetColorKey设置Color key。 CLR_INVALID是DDSetColorKey 和DDColorMatch函数中另一个有用的变量。如果在DDSetColorKey中以该值作为color key，位图左上角的像素就会作为color key使用。要想实现这一功能，需要调入位图文件All.bmp，将0,0处的像素值该为黑色，保存更改，然后如下改变对DDSetColorKey的调用： DDSetColorKey(lpDDSOne, CLR_INVALID);重新编译DDEX4，DDEX4就会使用0,0处的像素值作为color key了。<br><br>3.2 DDEX4中的动画<br>DDEX4利用All.bmp中的红色圆环调用updateFrame 函数来创建一个简单的动画。动画由圆环的3个位置组成。例子通过比较Win32中的GetTickCount和上次该函数开始运行的时间来判断是否重画哪个圆环，然后使用IDirectDrawSurface::BltFast方法将背景从屏外表面lpDDSOne位块传输到后台缓冲区，然后再使用已经设定好的color key将圆环块写入后台缓冲区。在所有的圆环都块写到后台缓冲区后，调用IDirectDrawSurface::Flip方法翻转后台缓冲区和主表面。<br><br>3.3 动态改变调色板<br>DDEX5描述了任何在程序运行时动态地改变调色板，尽管在游戏中这并不总是用到。DirectDraw确实能很好地控制调色板。DDEX5中的下述代码将All.bmp文件的下半部分中的调色板装入：<br><br></font><font face=宋体 color=#99ccff size=2>// First, set all colors as unused<br>for(i=0; i&lt;256; i++)<br>{<br>&nbsp;&nbsp;&nbsp; torusColors[i] = 0;<br>}<br>// lock the surface and scan the lower part (the torus area)<br>// and remember all the index's we find.<br>ddsd.dwSize = sizeof(ddsd);<br>while (lpDDSOne-&gt;Lock(NULL, &amp;ddsd, 0, NULL) == DDERR_WASSTILLDRAWING);<br>// Now search through the torus frames and mark used colors<br>for( y=480; y&lt;480+384; y++ )<br>{<br>&nbsp;&nbsp;&nbsp; for( x=0; x&lt;640; x++ )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; torusColors[((BYTE*)ddsd.lpSurface)[y*ddsd.lPitch+x]] = 1;<br>&nbsp;&nbsp;&nbsp; }<br>}<br>lpDDSOne-&gt;Unlock(NULL);</font><font face=Tahoma size=2><br><br>　　数组torusColors用于指定All.bmp中的下半部分调色板的索引值，数组在使用之前都初始化为0。然后锁定屏外表面来检测某颜色索引值是否已用。数组torusColors开始于位图的第0行第480列，数组中的颜色索引值由位图表面放置于内存的位置的一个字节决定，该位置由DDSURFACEDESC 结构中的lpSurface成员变量来决定，lpSurface指向对应于位图（0,480）处的内存地址(y*lPitch+x)。数组中设定的颜色索引值用来检测调色板中哪些颜色被替换。因为背景和红色圆环之间没有公用的颜色，所以只有那些同圆环联在一起的颜色值才会被替换。<br><br>3.4 替换调色板<br>DDEX5中的updateFrame函数同DDEX4中的基本相同，先将背景块写入后台缓冲区，再将3个红色圆环块写到前景。但在翻转表面之前，updateFrame用doInit函数创建的调色板索引值来改变主表面的调色板，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>// Change the palette<br>if(lpDDPal-&gt;GetEntries( 0, 0, 256, pe ) != DD_OK)&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp; return;<br>}<br><br>for(i=1; i&lt;256; i++)<br>{<br>&nbsp;&nbsp;&nbsp; if(!torusColors[i])&nbsp;<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; pe[i].peRed = (pe[i].peRed+2) % 256;<br>&nbsp;&nbsp;&nbsp; pe[i].peGreen = (pe[i].peGreen+1) %256;<br>&nbsp;&nbsp;&nbsp; pe[i].peBlue = (pe[i].peBlue+3) % 256;<br>}<br><br>if(lpDDPal-&gt;SetEntries( 0, 0, 256, pe) != DD_OK)<br>&nbsp;&nbsp;&nbsp; return;<br></font><font face=Tahoma size=2><br>IDirectDrawPalette::GetEntries方法在DirectDrawPalette对象中查询调色板的值，因为pe指向的调色板实体的值有效，方法就返回DD_OK，程序继续运行。然后循环检测torusColors在初始化中是否被设为1，如果索引值被设为1，由pe指向的调色板的红色、绿色、蓝色的值就被替换。在所有的被标记的调色板实体替换完毕后，再调用IDirectDrawPalette::SetEntries方法来真正改变DirectDrawPalette中的实体。如果该调色板已经设给主表面，上面的改变就会立即完成。完成了这一工作，剩下的就是同前面一样的翻转表面了。<br><br><strong>四 使用覆盖表面</strong><br>　　本例将使用DirectX SDK包含的Mosquito范例程序一步一步地说明怎样在程序中使用DirectDraw和硬件支持的覆盖表面。Mosquito使用覆盖表面的翻转链而没有位块传输到主表面将运动位图显示在桌面上。Mosquito程序调整覆盖表面的特征以适应硬件的限制。<br><br>4.1 创建一个主表面<br>要使用覆盖表面，必须先要初始化一个主表面，覆盖表面将显示在该主表面上。Mosquito用如下代码创建了一个主表面：<br><br></font><font face=宋体 color=#99ccff size=2>// Zero-out the structure and set the dwSize member.<br>ZeroMemory(&amp;ddsd, sizeof(ddsd));<br>ddsd.dwSize = sizeof(ddsd);<br>// Set flags and create a primary surface.<br>ddsd.dwFlags = DDSD_CAPS;<br>ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;<br>ddrval = g_lpdd-&gt;CreateSurface(&amp;ddsd, &amp;g_lpddsPrimary,NULL );</font><font face=Tahoma size=2><br><br>程序先初始化将要使用的DDSURFACEDESC结构，然后设定适当的标志调用IDirectDraw2::CreateSurface方法创建主表面。在对该方法的调用中，第一个参数是描述将要创建的表面的DDSURFACEDESC结构的指针；第二个参数是一个变量的指针，如果调用成功，该变量将接收IDirectDrawSurface接口的指针；第三个参数设为NULL表明没有COM集合。<br><br>4.2 检测硬件对覆盖的支持<br>初始化DirectDraw后，需要检测设备是否支持覆盖表面。因为DirectDraw不能仿真覆盖，所以如果硬件不支持覆盖，就不能继续下面的工作。你可以用IDirectDraw2::GetCaps方法获取硬件设备驱动程序的能力检测覆盖支持。在调用该方法之后，查看DDCAPS结构中的dwFlags成员是否包含有DDCAPS_OVERLAY标志。若有就表明支持覆盖，否则就不支持。<br>下面的代码是Mosquito程序中的一部分，它表明了怎样检测硬件的覆盖支持能力：<br><br></font><font face=宋体 color=#99ccff size=2>BOOL AreOverlaysSupported()<br>{<br>&nbsp;&nbsp;&nbsp; DDCAPS capsDrv;<br>&nbsp;&nbsp;&nbsp; HRESULT ddrval;<br>&nbsp;&nbsp;&nbsp; // Get driver capabilities to determine Overlay support.<br>&nbsp;&nbsp;&nbsp; ZeroMemory(&amp;capsDrv, sizeof(capsDrv));<br>&nbsp;&nbsp;&nbsp; capsDrv.dwSize = sizeof(capsDrv);<br>&nbsp;&nbsp;&nbsp; ddrval = g_lpdd-&gt;GetCaps(&amp;capsDrv, NULL);<br>&nbsp;&nbsp;&nbsp; if (FAILED(ddrval))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; // Does the driver support overlays in the current mode?<br>&nbsp;&nbsp;&nbsp; // (Currently the DirectDraw emulation layer does not support overlays.<br>&nbsp;&nbsp;&nbsp; // Overlay related APIs will fail without hardware support).<br>&nbsp;&nbsp;&nbsp; if (!(capsDrv.dwCaps &amp; DDCAPS_OVERLAY))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br><br>&nbsp;&nbsp;&nbsp; return TRUE;<br>}</font><font face=Tahoma size=2><br><br>程序首先调用IDirectDraw2::GetCaps方法获取设备驱动程序的能力。第一个参数是DDCAPS结构的地址指针；因为程序不需要关仿真的信息，所以第二个参数就设为NULL。获取驱动程序的能力后，程序使用了逻辑&#8220;与&#8221;来检查dwFlags成员是否包含有DDCAPS_OVERLAY标志。若否，程序返回FALSE表明失败。若是，就返回TRUE表明显示设备支持覆盖表面。<br><br>4.3 创建一个覆盖表面<br>如果知道显示设备支持覆盖表面，就可以创建一个。因为没有指明设备怎样支持覆盖表面的标准，所以不能够期望创建任意大小的像素格式的表面。另外，也不要期望第一次创建覆盖表面就会成功。因此，必须作好准备进行多次创建的尝试，直到有一个能够工作为止。<br>Mosquito程序在创建表面时遵循&#8220;best case to worst case&#8221;的原则，首先尝试创建一个三缓冲页翻转复杂覆盖表面。如果尝试失败，程序就改变方法尝试用其它通用的迅速格式来配置。下面的代码就是这一思路的表现：<br><br></font><font face=宋体 color=#99ccff size=2>ZeroMemory(&amp;ddsdOverlay, sizeof(ddsdOverlay));<br>ddsdOverlay.dwSize = sizeof(ddsdOverlay);<br>ddsdOverlay.dwFlags= DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH|DDSD_BACKBUFFERCOUNT| DDSD_PIXELFORMAT;<br>ddsdOverlay.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP|DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;<br>ddsdOverlay.dwWidth =320;<br>ddsdOverlay.dwHeight =240;<br>ddsdOverlay.dwBackBufferCount=2;<br>// Try to create an overlay surface using one of the pixel formats in our<br>// global list.<br>i=0;<br>do{<br>&nbsp;&nbsp;&nbsp; ddsdOverlay.ddpfPixelFormat=g_ddpfOverlayFormats[i];<br>&nbsp;&nbsp;&nbsp; // Try to create the overlay surface<br>&nbsp;&nbsp;&nbsp; ddrval = g_lpdd-&gt;CreateSurface(&amp;ddsdOverlay,&amp;g_lpddsOverlay, NULL);<br>} while( FAILED(ddrval) &amp;&amp; (++i &lt; NUM_OVERLAY_FORMATS));</font><font face=Tahoma size=2><br><br>程序设置DDSURFACEDESC结构中的标志和值以反映三缓冲页翻转复杂覆盖表面，然后执行循环。在循环中，程序尝试用各种常用的像素格式创建要求的表面。如果尝试成功，循环就终止。如果尝试失败，说明很有可能是显示硬件没有足够的显示内存支持三缓冲的方案或者硬件根本就不支持翻转覆盖表面。在这种情况下，在最小要求的配置下使用一个单一的非翻转覆盖表面，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>// If we failed to create a triple buffered complex overlay surface, try<br>// again with a single non-flippable buffer.<br>if(FAILED(ddrval))<br>{<br>&nbsp;&nbsp;&nbsp; ddsdOverlay.dwBackBufferCount=0;<br>&nbsp;&nbsp;&nbsp; ddsdOverlay.ddsCaps.dwCaps=DDSCAPS_OVERLAY| DDSCAPS_VIDEOMEMORY;<br>&nbsp;&nbsp;&nbsp; ddsdOverlay.dwFlags= DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT;<br>&nbsp;&nbsp;&nbsp; // Try to create the overlay surface<br>&nbsp;&nbsp;&nbsp; ddrval = g_lpdd-&gt;CreateSurface(&amp;ddsdOverlay,&amp;g_lpddsOverlay, NULL);<br>&nbsp;&nbsp;&nbsp; i=0;<br>&nbsp;&nbsp;&nbsp; do<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddsdOverlay.ddpfPixelFormat=g_ddpfOverlayFormats[i];ddrval = g_lpdd-&gt;CreateSurface(&amp;ddsdOverlay, &amp;g_lpddsOverlay, NULL);<br>&nbsp;&nbsp;&nbsp; }while( FAILED(ddrval)&amp;&amp; (++i &lt; NUM_OVERLAY_FORMATS) ); // We couldn't create an overlay surface. Exit, returning failure.<br>&nbsp;&nbsp;&nbsp; if (FAILED(ddrval))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br>}</font><font face=Tahoma size=2><br><br>　　上面的代码对DDSURFACEDESC结构中的标志和值复原来反映一个单一的非翻转覆盖表面，然后通过像素格式的循环尝试创建表面。如果创建表面成功，循环就停止。如果不成功，程序返回FALSE表明创建表面失败。在成功地创建覆盖表面之后，就可将位图装入其中以供显示。<br><br>4.4 显示覆盖表面<br>创建了覆盖表面之后就可以显示它了。通常，硬件在用于显示覆盖的矩形的位置和像素格式上加上对齐约束。另外，还需要经常通过调整目的矩形的宽度来说明最小要求的拉伸因子以成功地显示覆盖表面。Mosquito程序按照以下的步骤准备和显示覆盖表面。<br><br>4.4.1、检测显示的最小要求<br>大部分的显示硬件在显示覆盖时都会加上约束。你必须很仔细地调整覆盖使之满足这些约束。可以通过调用IDirectDraw2::GetCaps方法获得有关这些约束的信息。该方法填充的结构DDCAPS包含了有关覆盖能力和使用约束的信息。不同硬件的约束是不同的，因此必须始终要查看包含在dwFlags成员的标志以确定附加的是哪一种约束。<br>　　Mosquito程序开始时先获取硬件的能力，然后采用基于最小拉伸因子的方法，如下所示：<br><br></font><font face=宋体 color=#99ccff size=2>// Get driver capabilities<br>ddrval = g_lpdd-&gt;GetCaps(&amp;capsDrv, NULL);<br>if (FAILED(ddrval))<br>&nbsp;&nbsp;&nbsp; return FALSE;<br><br>// Check the minimum stretch and set the local variable accordingly.<br>if(capsDrv.dwCaps &amp; DDCAPS_OVERLAYSTRETCH)<br>&nbsp;&nbsp;&nbsp; uStretchFactor1000 = (capsDrv.dwMinOverlayStretch&gt;1000) ? capsDrv.dwMinOverlayStretch : 1000;<br>else<br>&nbsp;&nbsp;&nbsp; uStretchFactor1000 = 1000;</font><font face=Tahoma size=2><br><br>上面的代码调用IDirectDraw2::GetCaps方法获取硬件的能力。在本例中，第一个参数是DDCAPS结构的指针；第二个参数是NULL，表明了不需要获取有关仿真的信息。程序在一个临时变量中保留了最小拉伸因子以备以后之用。如果驱动程序报告出的拉伸因子大于1000，就表明驱动程序要求所有的目的矩形沿X轴的方向拉伸。例如，若拉伸因子是1.3，源矩形宽320个像素，目的矩形就必须至少要有416（320X1.3=416）个像素的宽。如果驱动程序报告出的拉伸因子小于1000，就表明驱动程序能够显示比源矩形小的覆盖，但不能伸展覆盖。<br>下面的代码是测定描述驱动程序的大小对齐约束的值：<br></font><font face=宋体 color=#99ccff size=2><br>// Grab any alignment restrictions and set the local variables acordingly.<br>uSrcSizeAlign = (capsDrv.dwCaps &amp; DDCAPS_ALIGNSIZESRC)?capsDrv.dwAlignSizeSrc:0;<br>uDestSizeAlign= (capsDrv.dwCaps &amp; DDCAPS_ALIGNSIZESRC)</font><font face=Tahoma size=2><br><br>?capsDrv.dwAlignSizeDest:0; 例中使用了更多的临时变量来保存从dwAlignSizeSrc和dwAlignSizeDest成员中获得的大小对齐约束。这些值提供了有关像素宽度对齐约束的信息，并且在以后设定源矩形和目的矩形的大小时需要用到。源矩形和目的矩形必须是这些值的倍数。<br>最后，程序测定描述目的矩形边界对齐约束的值：<br><br></font><font face=宋体 color=#99ccff size=2>// Set the "destination position alignment" global so we won't have to<br>// keep calling GetCaps() every time we move the overlay surface.<br>if (capsDrv.dwCaps &amp; DDCAPS_ALIGNBOUNDARYDEST)<br>&nbsp;&nbsp;&nbsp; g_dwOverlayXPositionAlignment= capsDrv.dwAlignBoundaryDest;<br>else<br>&nbsp;&nbsp;&nbsp; g_dwOverlayXPositionAlignment= 0;</font><font face=Tahoma size=2><br><br>上面的代码使用了一个全局变量来保存目的矩形边界约束的值，该值是从dwAlignBoundaryDest成员中的得来的，在以后程序重新放置覆盖时将会用到。你必须设定目的矩形左上角的X坐标在像素格式上同该值对齐。也就是说，如果该值是4，就只能指定左上角的X坐标为0，4，8，12等像素宽的目的矩形。Mosquito程序首先在0，0处显示覆盖，于是在第一次显示覆盖之前就不需要获取约束信息。但是因为不同应用程序的实现过程可能不同，所以你可能需要在显示覆盖之前检查这些信息以调整目的矩形。<br><br>4.4.2、设置源矩形和目的矩形<br>在获得了驱动程序的覆盖约束之后，就应该设定有关源矩形和目的矩形的值，确保能够正确显示覆盖。下面的代码就设定了源矩形的特征：<br><br></font><font face=宋体 color=#99ccff size=2>// Set initial values in the source RECT.<br>rs.left=0;<br>rs.top=0;<br>rs.right = 320;<br>rs.bottom = 240;<br>// Apply size alignment restrictions, if necessary.<br>if (capsDrv.dwCaps &amp; DDCAPS_ALIGNSIZESRC &amp;&amp;uSrcSizeAlign)<br>&nbsp;&nbsp;&nbsp; rs.right -= rs.right % uSrcSizeAlign;</font><font face=Tahoma size=2><br><br>上面的代码设置了包含整个表面大小的初始值。如果设备驱动程序要求大小对齐，程序就调整源矩形来保证。程序调整了源矩形的宽度使之比初始值要小，这是因为如果不是完全重新创建表面，就不能够扩展宽度。<br>在设定了源矩形的大小后，需要设置和调整目的矩形的大小。这一过程需要稍微多一点的工作，因为目的矩形可能需要先拉伸再调整以符合大小对齐约束。下面的代码根据最小拉伸因子来设置和调整目的矩形的大小：<br><br></font><font face=宋体 color=#99ccff size=2>// Set up the destination RECT, starting with the source RECT values.<br>// We use the source RECT dimensions instead of the surface dimensions in<br>// case they differ.<br>rd.left=0;<br>rd.top=0;<br>rd.right = (rs.right*uStretchFactor1000+999)/1000;<br>// (Adding 999 avoids integer truncation problems.)<br>// (This isn't required by DDraw, but we'll stretch the<br>// height, too, to maintain aspect ratio).<br>rd.bottom = rs.bottom*uStretchFactor1000/1000;</font><font face=Tahoma size=2><br><br>前面的代码先设置目的矩形的左上角位置，再根据最小拉伸因子设定目的矩形的宽度。根据拉伸因子调整矩形时，注意程序在宽度和拉伸因子的乘积上又加了999，这是为了避免出现整数截断，整数截断会导致矩形同最小拉伸因子的要求不一致。程序在拉伸宽度后也拉伸了矩形的高度。不过，对高度的拉伸并不是必须的，这里只是为了保持位图的长宽比率避免出现失真的现象。<br>拉伸目的矩形后，程序对其进行调整以保持和大小对齐约束一致，下面是相应的代码：<br><br></font><font face=宋体 color=#99ccff size=2>// Adjust the destination RECT's width to comply with any imposed<br>// alignment restrictions.<br>if (capsDrv.dwCaps &amp; DDCAPS_ALIGNSIZEDEST &amp;&amp;uDestSizeAlign)<br>&nbsp;&nbsp;&nbsp; rd.right = (int)((rd.right+uDestSizeAlign-1)/uDestSizeAlign)*uDestSizeAlign;</font><font face=Tahoma size=2><br><br>程序检测硬件能力的标志，查看驱动程序是否加了矩形大小对齐约束。如果是，就增加目的矩形的宽度使之满足大小对齐约束。这里对矩形的调整是扩展其宽度而不能减少其宽度，因为减少宽度可能会导致目的矩形比最小拉伸因子要求的还要小，从而引起显示覆盖表面失败。<br><br>4.4.3、显示覆盖表面 在设置了源矩形和目的矩形后，就可以显示覆盖了。如果显示覆盖之前的准备工作正确，显示覆盖会很简单。Mosquito程序用如下的代码来显示覆盖：<br><br></font><font face=宋体 color=#99ccff size=2>&nbsp;// Set the flags we'll send to UpdateOverlay dwUpdateFlags = DDOVER_SHOW | DDOVER_DDFX;<br>// Does the overlay hardware support source color keying?<br>// If so, we can hide the black background around the image.<br>// This probably won't work with YUV formats<br>if (capsDrv.dwCKeyCaps &amp; DDCKEYCAPS_SRCOVERLAY)<br>&nbsp;&nbsp;&nbsp; dwUpdateFlags |= DDOVER_KEYSRCOVERRIDE;<br>// Create an overlay FX structure so we can specify a source color key.<br>// This information is ignored if the DDOVER_SRCKEYOVERRIDE flag isn't set.<br>ZeroMemory(&amp;ovfx, sizeof(ovfx));<br>ovfx.dwSize = sizeof(ovfx);<br>ovfx.dckSrcColorkey.dwColorSpaceLowValue=0; // Specify black as the color key<br>ovfx.dckSrcColorkey.dwColorSpaceHighValue=0;<br>// Call UpdateOverlay() to displays the overlay on the screen.<br>ddrval = g_lpddsOverlay-&gt;UpdateOverlay(&amp;rs, g_lpddsPrimary, &amp;rd, dwUpdateFlags, &amp;ovfx);<br>if(FAILED(ddrval))<br>&nbsp;&nbsp;&nbsp; return FALSE;</font><font face=Tahoma size=2><br><br>程序开始在临时变量dwUpdateFlags中设定了DDOVER_SHOW和DDOVER_DDFX标志，指明该覆盖是第一次显示，硬件应该使用包含在DDOVERLAYFX结构中的效果信息完成这一工作。然后，程序检查DDCAPS结构确定覆盖是否支持源Color Key。如果是，DDOVER_KEYSRCOVERRIDE标志就包含在dwUpdateFlags变量中利用源Color Key，程序也据此设置Color Key。<br>准备工作完成之后，程序调用IDirectDrawSurface3::UpdateOverlay方法来显示覆盖。在对该方法的调用中，第一个参数和第三个参数是已调整的源矩形和目的矩形的地址。第二个参数是覆盖显示在其上的主表面的地址。第四个参数是包括了放置于此前准备的dwUpdateFlags变量中的标志。第五个参数是DDOVERLAYFX结构的地址，该结构中的成员将设定同那些标志相匹配。<br>如果硬件只支持一个覆盖表面而且该表面正在使用，UpdateOverlay方法就会失败，并返回DDERR_OUTOFCAPS。另外，有可能硬件报告出的最小拉伸因子过小，在UpdateOverlay方法失败后，你就需要尝试减少目的矩形的宽度来应付这种可能性。不过，这种情况很少发生，在Mosquito中也只是简单地返回一个错误信息。<br><br>4.5 更新覆盖的显示位置<br>显示覆盖表面之后，有时可能就不需要对覆盖左其它的操作了。但有些软件还需要重新放置覆盖，改变覆盖的显示位置。Mosquito程序就使用IDirectDrawSurface3::SetOverlayPosition方法重新放置覆盖，代码如下：<br><br></font><font face=宋体 color=#99ccff size=2>// Set X- and Y-coordinates<br>...... // We need to check for any alignment restrictions on the X position<br>// and align it if necessary.<br>if (g_dwOverlayXPositionAlignment)<br>&nbsp;&nbsp;&nbsp; dwXAligned = g_nOverlayXPos- g_nOverlayXPos % g_dwOverlayXPositionAlignment;<br>else<br>&nbsp;&nbsp;&nbsp; dwXAligned = g_nOverlayXPos;<br>// Set the overlay to its new position.<br>ddrval = g_lpddsOverlay-&gt;SetOverlayPosition(dwXAligned,g_nOverlayYPos);<br>if (ddrval == DDERR_SURFACELOST)<br>{<br>&nbsp;&nbsp;&nbsp; if (!RestoreAllSurfaces())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>}</font><font face=Tahoma size=2><br><br>程序开始对齐矩形以满足可能存在的任何目的矩形边界对齐约束。当程序此前调用IDirectDraw2::GetCaps方法时，全局变量g_dwOverlayXPositionAlignment已经设定为同DDCAPS结构中dwAlignBoundaryDest成员所报告出的值相等。如果存在目的矩形约束，程序就据此调整新的X坐标为像素对齐的。若不满足要求，覆盖表面就不能显示。<br>在完成了对X坐标的调整之后，程序调用IDirectDrawSurface3::SetOverlayPosition方法重新放置覆盖。在调用中第一个参数是对齐的新的X坐标，第二个参数的新的Y坐标。这些值表明了覆盖左上角新的位置。这里并不需要取得宽度和高度信息，因为DirectDraw在开始用IDirectDrawSurface3::UpdateOverlay方法显示覆盖时就已经获得了表面大小的信息。如果因为一个或多个表面丢失而引起的重新放置覆盖表面的失败，Mosquito程序就调用一个应用定义的函数来恢复这些表面并重新装入它们的位图。<br>注意，不要使用太靠近目标表面的右、下边界的坐标。因为IDirectDraw2::SetOverlayPosition方法并不执行剪切功能，所以使用那些可能导致覆盖超出目标表面边界的坐标会引起调用的失败，并返回DDERR_INVALIDPOSITION。<br><br>4.6 隐藏覆盖表面<br>如果不再需要一个覆盖表面或只想不让覆盖可见，就可以设定适当的标志调用IDirectDrawSurface3::UpdateOverlay方法来隐藏该覆盖表面。Mosquito用以下代码隐藏覆盖表面并准备关闭应用程序：<br><br></font><font face=宋体 color=#99ccff size=2>void DestroyOverlay()<br>{<br>&nbsp;&nbsp;&nbsp; if (g_lpddsOverlay)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Use UpdateOverlay() with the DDOVER_HIDE flag to remove an overlay<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // from the display.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_lpddsOverlay-&gt;UpdateOverlay(NULL,g_lpddsPrimary, NULL, DDOVER_HIDE, NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_lpddsOverlay-&gt;Release();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_lpddsOverlay=NULL;<br>&nbsp;&nbsp;&nbsp; }<br>}</font><font face=Tahoma size=2><br><br>在调用IDirectDrawSurface3::UpdateOverlay时，对源矩形和目的矩形指定了NULL，因为在隐藏覆盖的过程中不需要源矩形和目的矩形。<br>同理，第五个参数也被指定为NULL是因为不使用覆盖效果。第二个参数是目标表面的指针。最后，程序在第四个参数使用DDOVER_HIDE标志表明该覆盖将从视口中取消。<br>　　程序在隐藏覆盖之后，释放了它的IDirectDrawSurface3接口，并且将全局变量设为NULL使之变得无效。对于Mosquito程序来说，覆盖就不再需要了。如果在应用程序中还需要使用该覆盖，就只需简单地隐藏覆盖，而不要释放它，然后在需要的时候再重新显示。<br><br><strong>五 DirectDraw中其它的DirectDraw范例</strong><br>要熟练掌握有关DirectDraw的应用，还应该多研究包含在DirectX<br>SDK:之中的下述范例。<br>1、Stretch<br>描述了怎样在一个窗口中创建一个非独占模式的动画，它具有剪切位块传输和拉伸剪切位块传输的功能。<br>2、Donut<br>描述了多个独占模式的应用同非独占模式应用之间的交互。<br>3、Wormhole<br>该范例描述了详细的调色板动画。<br>4、Dxview<br>详细描述了怎样获取显示硬件的能力。<br>　 其它的还有Duel、Iklowns、Foxbear、Palette和Flip2d等，只要多这些范例多加分析，掌握DirectX最基本的技术DirectDraw是不难的。</font></td>
                                </tr>
                            </tbody>
                        </table>
                        </center></div>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86487.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:41 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86487.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何实现游戏截屏功能</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86486.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:33:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86486.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86486.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86486.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86486.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86486.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/jietu.htm">http://dev.gameres.com/Program/Visual/2D/jietu.htm</a><br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <p align=center><font face=Tahoma color=#ffffcc><strong>如何实现游戏截屏功能</strong></font> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <div align=center>
                        <center>
                        <table cellSpacing=0 cellPadding=0 width="95%" border=0>
                            <tbody>
                                <tr>
                                    <td width="100%"><font face=Tahoma size=2><br>　　现在很多游戏都提供一种截屏的功能，用来截取游戏中的画面，那么这是如何实现的呢？其实就是把游戏当前屏幕的数据存成一个图片文件；在这里我给出一段源程序，它实现了DirectDraw（16位模式）下的的游戏截屏。生成的文件格式为ＢＭＰ，程序有比较详细的注释，请各位自己看吧。<br><br>　　现在很多游戏都提供一种截屏的功能，用来截取游戏中的画面，那么这是如何实现的呢？其实就是把游戏当前屏幕的数据存成一个图片文件；在这里我给出一段源程序，它实现了DirectDraw（16位模式）下的的游戏截屏。生成的文件格式为ＢＭＰ，程序有比较详细的注释，请各位自己看吧。<br><br></font><font face=宋体 color=#99ccff size=2>bool Is555; // 是否是565模式，这个变量需要用者填写<br><br>// 功能：将一个16位的DirectDraw表面，存为一张24位BMP位图 （传入主表面即截屏）<br>// 输入：表面指针，输出的文件名<br>// 输出：是否成功<br>bool SaveToBitmapFile(LPDIRECTDRAWSURFACE lpSurface, char* filename)<br>{<br>&nbsp;&nbsp;&nbsp; WORD* lpBuffer; // 表面指针<br>&nbsp;&nbsp;&nbsp; int nPitch; // 表面跨距<br>&nbsp;&nbsp;&nbsp; int nWidth, nHeight; // 表面宽高<br><br>&nbsp;&nbsp;&nbsp; // 打开文件s<br>&nbsp;&nbsp;&nbsp; FILE* fp;<br>&nbsp;&nbsp;&nbsp; if( (fp=fopen(filename, "wb")) != NULL )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 锁定表面<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DDSURFACEDESC ddsd;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ddsd.dwSize = sizeof(ddsd);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HRESULT ddrval = lpSurface-&gt;Lock( NULL, &amp;ddsd, DDLOCK_WAIT, NULL );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ddrval == DD_OK )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpBuffer = (WORD *)ddsd.lpSurface;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nWidth = ddsd.dwWidth;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nHeight = ddsd.dwHeight;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nPitch = ddsd.lPitch &gt;&gt; 1; //lPitch以Byte为单位，GraphPitch以WORD为单位。所以GraphPitch = lPitch / 2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 保存文件头<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BITMAPFILEHEADER FileHeader;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileHeader.bfType = 'BM';<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileHeader.bfSize = nWidth * nHeight * 3 + 0x36;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileHeader.bfReserved1 = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileHeader.bfReserved2 = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileHeader.bfOffBits = 0x36;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fwrite(&amp;FileHeader, sizeof(BITMAPFILEHEADER), 1, fp);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 保存文件信息<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BITMAPINFOHEADER Header;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biSize = sizeof(BITMAPINFOHEADER); // 结构的大小<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biWidth = nWidth; // 宽<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biHeight = nHeight; // 高<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biPlanes = 1; // 固定<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biBitCount = 24; // 颜色数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biCompression = BI_RGB; // 是否压缩<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biSizeImage = nWidth * nHeight * 3; // 图片的大小<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biXPelsPerMeter = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biYPelsPerMeter = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biClrUsed = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Header.biClrImportant = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fwrite(&amp;Header, Header.biSize, 1, fp);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 写入具体内容(从下向上存放)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fseek(fp, 0x36, SEEK_SET);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD word;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpBuffer += nWidth * (nHeight - 1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i</font><nheight; i++)<br><font face=宋体 color=#99ccff size=2> {<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><font face=宋体 color=#99ccff size=2>for(int j=0; j</font><nwidth; j++)<br><font face=宋体 color=#99ccff size=2> {<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>word = *lpBuffer;<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>fputc( GetBlue( word ), fp); // 蓝<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>fputc( GetGreen( word ), fp); // 绿<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>fputc( GetRed( word ), fp); // 红<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>lpBuffer++;<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>}<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>lpBuffer -= nPitch*2; // 指针转到上一行的开始<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>}<br><br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>fclose(fp);<br><br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>// 解锁表面<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>ddrval = lpSurface-&gt;Unlock( NULL );<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>return true;<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>}<br><br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>return false;<br>}<br><br>inline unsigned char GetRed(WORD color)<br>{<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>if( Is555 )<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>return (color&gt;&gt;7) &amp; 0xff;<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>else<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>return (color&gt;&gt;8) &amp; 0xff;<br>}<br><br>inline unsigned char GetGreen(WORD color)<br>{<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>if( Is555 )<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>return (color&gt;&gt;2) &amp; 0xff;<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>else<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>return (color&gt;&gt;3) &amp; 0xff;<br>}<br><br>inline unsigned char GetBlue(WORD color)<br>{<br></font><font face=宋体 color=#99ccff size=2>&nbsp;&nbsp;&nbsp; </font><nheight; i++)<br><nwidth; j++)<br><font face=宋体 color=#99ccff size=2>return (color &amp; 0x1f) &lt;&lt; 3;<br>}<br></font><font face=Tahoma size=2><br>------------------------<br>金点时空<br>softboy<br>2001.5.9<br>http://www.gpgame.com<br>------------------------<br></font></td>
                                </tr>
                            </tbody>
                        </table>
                        </center></div>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86486.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:33 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86486.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DirectDraw编程技巧</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86485.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:30:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86485.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86485.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86485.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86485.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86485.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/articles.asp?style=a&amp;page=2">http://dev.gameres.com/articles.asp?style=a&amp;page=2</a><a href="http://dev.gameres.com/Program/Visual/2D/DrawAdd.htm"><br>http://dev.gameres.com/Program/Visual/2D/DrawAdd.htm</a><br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <p align=center><strong><font face=Tahoma color=#ffffcc>DirectDraw编程技巧</font></strong> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <div align=center>
                        <center>
                        <table cellSpacing=0 cellPadding=0 width="95%" border=0>
                            <tbody>
                                <tr>
                                    <td width="100%"><font face=Tahoma size=2><br>使用IDirectDrawSurface::Lock( )就能让我们随心所欲，因为此函数可以允许我们直接修改页面。<br>　　Lock( )函数的用法如下：<br><br></font><font face=宋体 color=#99ccff size=2>HRESULT Lock(<br>&nbsp;&nbsp;&nbsp; LPRECT lpDestRect,<br>&nbsp;&nbsp;&nbsp; LPDDSURFACEDESC lpDDSurfaceDesc,<br>&nbsp;&nbsp;&nbsp; DWORD dwFlags,<br>&nbsp;&nbsp;&nbsp; HANDLE hEvent<br>);<br></font><font face=Tahoma size=2><br>　　第一个参数为一个指向某个RECT的指针，它指定将被锁定的页面区域。如果该参数为 NULL，整个页面将被锁定。<br>　　第二个参数为一个 DDSURFACEDESC结构的地址，将被填充页面的相关信息。<br>　　第三个参数，即dwFlags，还是象以前一样给它DDLOCK_WAIT。<br>　　第四个参数规定要为NULL。<br>　　现在举一个例子来说明怎样使用Lock( )，我们的目标是使lpDDSBack半透明地浮现在lpDDSBuffer上。先看看完整的锁屏部分（注意，这一节只讨论24和32位色下如何操作）：<br><br></font><font face=宋体 color=#99ccff size=2>DDSURFACEDESC ddsd, ddsd2; //DirectDraw页面描述<br>ZeroMemory(&amp;ddsd, sizeof(ddsd)); //ddsd用前要清空<br>ddsd.dwSize = sizeof(ddsd); //DirectDraw中的对象都要这样<br>ZeroMemory(&amp;ddsd2, sizeof(ddsd2));<br>ddsd2.dwSize = sizeof(ddsd2);<br>lpDDSBuffer-&gt;Lock(NULL, &amp;ddsd, DDLOCK_WAIT, NULL); //Lock!<br>lpDDSBack-&gt;Lock(NULL, &amp;ddsd2, DDLOCK_WAIT, NULL);<br><br>BYTE *Bitmap = (BYTE*)ddsd.lpSurface; //Lock后页面的信息被存在这里，请注意<br>//这个指针可能每次Lock( )后都不同！<br>BYTE *Bitmap2 = (BYTE*)ddsd2.lpSurface;</font><font face=Tahoma size=2><br><br>　　锁完页面后，Bitmap数组的存储格式是这样的：如为32位色则页面上坐标为(x,y)的点的R/G/B值分别存在Bitmap的y*ddsd.lPitch+x*4，y*ddsd.lPitch+x*4+1，y*ddsd.lPitch+x*4+2处；如为24位色则页面上坐标为(x,y)的点的R/G/B值分别存在Bitmap的y*ddsd.lPitch+x*3，y*ddsd.lPitch+x*3+1，y*ddsd.lPitch+x*3+2处。所以，现在我们就可以发挥想象，做出想要的一切效果了，比如说动态光照(将一目标页面按光照表改变亮度即可)！下面是接下来的代码(32位色时)：<br><br></font><font face=宋体 color=#99ccff size=2>int pos;<br>for (int y=0;y&lt;480; y++)<br>{<br>&nbsp;&nbsp;&nbsp; pos=y*ddsd.lPitch;<br>&nbsp;&nbsp;&nbsp; for (int x=0; x&lt;640; x++)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bitmap[pos] =(Bitmap[pos]+Bitmap2[pos])&gt;&gt;1; //改R<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pos++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bitmap[pos] =(Bitmap[pos]+Bitmap2[pos])&gt;&gt;1; //改G<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pos++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bitmap[pos] =(Bitmap[pos]+Bitmap2[pos])&gt;&gt;1; //改B<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pos+=2;//到下一个R处<br>&nbsp;&nbsp;&nbsp; }<br>}<br>lpDDSBack-&gt;Unlock(&amp;ddsd2); //Unlock!<br>lpDDSBuffer-&gt;Unlock(&amp;ddsd);</font><font face=Tahoma size=2><br><br>　　由于使用Lock后DirectDraw要锁定页面，在没有使用Unlock( )前我们是无法用其他办法如Blt来修改页面的。所以用完Lock( )要赶快象上面的程序那样Unlock( )。Unlock的方法很简单，lpDDSXXX-&gt;Unlock(LPDDSURFACEDESC lpDDSurfaceDesc)即可。<br><br>7.2 程序的提速<br>　　上面的程序看起来好象很简单，但运行速度很可能会很慢，即使你直接用汇编重写也不会快多少。原因是读显存非常慢，写显存的速度也比写内存慢。解决这个问题的方法是：<br>(1)把除了主页面外的所有页面放在内存中。（初始化页面时将ddsd.ddsCaps.dwCaps中的 DDSCAPS_OFFSCREENPLAIN后再或( | )一项"DDSCAPS_SYSTEMMEMORY"）这样做的另一个好处是你Lock( )一次后就永远得到了页面指针，而且然后一Unlock( )就又可以使用Blt了，你就拥有了两种改变页面的手段。<br>(2)将后台缓冲改为一个普通的离屏页面。<br>(3)将Flip( )改用BltFast( )函数实现。当然你也可以直接用memcpy( )拷贝，这样做有时候会快一些。注意要一行一行地拷贝，比如说640x480x24位色全屏幕拷贝是这样的：<br><br></font><font face=宋体 color=#99ccff size=2>BYTE *pSrc=(BYTE *)ddsd_src.lpSurface;<br>BYTE *pDest=(BYTE *)ddsd_dest.lpSurface;<br><br>for (int y=0;y&lt;480;y++)<br>{<br>&nbsp;&nbsp;&nbsp; memcpy(pDest, pSrc, 1920); //若为32位色则为2560<br>&nbsp;&nbsp;&nbsp; pSrc+=ddsd_src.lPitch;<br>&nbsp;&nbsp;&nbsp; pDest+=ddsd_dest.lPitch;<br>}</font><font face=Tahoma size=2><br><br>　　看起来好像要重写很多东西，其实改动的部分并不多。这样改了之后整个程序的速度就会快很多，但还不能很好地满足全屏幕特效的要求，因为全屏幕特效实在很耗时间，只有用MMX指令重写速度才能比较快。所以在下面一章中，我们将介绍内嵌汇编和MMX指令。<br><br>7.3 排除错误的技巧<br>　　每个人都会犯错误，在编程中也如此，写完程序后第一次运行就直接通过的情况实在是不多的，偶尔出现一两次都是值得高兴的事。有错当然要改，但很多时候最难的并不是改正错误，而是找到错误，有时候写程序的时间还不如找错误的时间长。为了帮助大家节省一点时间，下面就讲一讲我的一点找错误的经验。<br>　　首先当然要说说常见的错误有哪些，最经常出现的是：漏分号、多分号、漏各种括号、多各种括号、"=="写成了"="（上面的错误看上去很弱智，不过你没犯过吗？）、数组（指针）越界（最常见的错误之一！）、变量越界、指针使用前未赋初值。有一点要注意的是Visual C++显示出的出错的那一行有可能不是真正出错的位置！<br>　　常用的找错办法就是先确认你刚刚改动了哪些语句，然后用/*和*/把可能出错的语句屏障掉，如果运行后还不通过就再扩大范围。即使有一段程序你觉得不可能有什么问题或以前工作正常也要试试将它屏障，有时就是在似乎最不可能出错的地方出了问题。<br>　　还有一种大家都经常用的找错办法就是把一些变量的值显示在屏幕上，或是把程序运行的详细过程存入文件中，出什么问题一目了然。如果再像QuakeIII一样用一个"控制台"显示出来就很酷了。<br>　　象其它编译器一样，Visual C++提供了变量观察（Watch）、单步执行（Step）等常规调试手段，当然你首先需要把工程设为Debug模式，在编译---放置可运行设置中可更改。但可惜的是在DirectDraw程序中这些方法不怎么好用。可能有的人会问我为什么不把程序改为在窗口模式下运行，但在窗口模式下你能Lock吗？你能随意改动显存吗？如果把这些语句屏障掉那可就太麻烦了。不过有两条调试语句可以在DirectDraw程序中调用，第一条就是assert。该语句的使用方法是assert（条件），你可以把它放到需要的地方，当条件不满足时就会显示一个对话框，说明在哪个程序哪一行出现了条件不满足，然后你可以选择继续或是忽略。第二条语句是OutputDebugString(要输出的字符串)，可以在屏幕下方编译窗口的调试那一栏显示这个字符串。<br><br>7.4 C++程序优化技巧<br>　　首先请注意一点：再好的语句上的优化，比如说使用汇编语言，也比不上算法上的优化所带来的巨大效益。算法的设计是国内有些编程人员的不足之处，所以我觉得对这方面不太熟悉的人都应该买本讲数据结构与算法的书来看看，不要抄了别人的A*算法就觉得自己的程序很先进了。在9.4节讲述了几种常用的算法，如果你感兴趣可以看看。<br>下面就转入正题，讲一讲一般的优化技巧吧：<br>(1) 使用内联函数。<br><br>(2)展开循环。<br><br></font><font face=宋体 color=#99ccff size=2>for (i = 0; i &lt; 100; i++)<br>{<br>&nbsp;&nbsp;&nbsp; do_stuff(i);<br>}<br><br></font><font face=宋体 size=2>可以展开成：</font><font face=宋体 color=#99ccff size=2><br>for (i = 0; i &lt; 100; )<br>{<br>&nbsp;&nbsp;&nbsp; do_stuff(i); i++;<br>&nbsp;&nbsp;&nbsp; do_stuff(i); i++;<br>&nbsp;&nbsp;&nbsp; do_stuff(i); i++;<br>&nbsp;&nbsp;&nbsp; do_stuff(i); i++;<br>&nbsp;&nbsp;&nbsp; do_stuff(i); i++;<br>}<br><br></font><font face=宋体 size=2>(3)运算强度减弱。</font><font face=宋体 color=#99ccff size=2><br>x = w % 8;<br>y = x * 33;<br>for (i = 0; i &lt; MAX; i++)<br>{<br>&nbsp;&nbsp;&nbsp; h = 14 * i;<br>&nbsp;&nbsp;&nbsp; cout&lt; }<br><br></font><font face=宋体 size=2>上面的程序这样改动可以大大加快速度：</font><font face=宋体 color=#99ccff size=2><br>x = w &amp; 7;<br>y = (x &lt;&lt; 5) + x; //&lt;&lt;比+的运算优先级低！<br>for (i = h = 0; i &lt; MAX; i++)<br>{<br>&nbsp;&nbsp;&nbsp; cout&lt; h += 14;<br>}</font><font face=Tahoma size=2><br><br>(4)查表。这种方法挺有用，特别是在DirectDraw程序中。比如说我们定义了一个函数f(x)可以返回x*x*x，其中x的范围是0~1，精度为0.001，那么我们可以建立一个数组a[1000]，a[t*1000]存储的是预先计算好的t*t*t的值，以后调用函数就可以用查找数组代替了。<br></font></td>
                                </tr>
                            </tbody>
                        </table>
                        </center></div>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86485.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:30 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86485.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动画程序编写——DirectDraw之旅（3）</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86484.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:26:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86484.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86484.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86484.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86484.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86484.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DDrawZL_3.htm">http://dev.gameres.com/Program/Visual/2D/DDrawZL_3.htm</a><br><br>
<table id=AutoNumber2 style="BORDER-COLLAPSE: collapse" height=8692 cellSpacing=0 cellPadding=0 width="85%" border=0>
    <tbody>
        <tr>
            <td width="100%" height=32>
            <p align=center><font color=#ffffee><strong>动画程序编写——DirectDraw之旅（3）</strong></font></p>
            </td>
        </tr>
        <tr>
            <td width="100%" height=18></td>
        </tr>
        <tr>
            <td width="100%" height=8564><font size=2>下面我们开始分析源程序：</font>
            <p><font size=2>下载源程序&nbsp; <font color=#ff0000>（编辑者：链接丢失）</font></font></p>
            <p><font size=2>属于Win32程序的基本框架的我们用蓝色标出，而用红色表出的是我们要重点学习的。下面的所有程序都是 FullScreenMode.cpp 文件中的内容，其中&#8220;IDB_DIRECTX&#8221;和&#8220;IDB_WinXP&#8221;都是图片资源的ID号，我想如何向程序中添加资源应该不用我多说了吧:)</font></p>
            <p><font color=#4898df size=2>工程文件：FullScreenMode.cpp</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>#define STRICT<br>#include &lt;windows.h&gt;<br>#include &lt;ddraw.h&gt;<br>#include &lt;mmsystem.h&gt;<br>#include "resource.h"<br>#include "ddutil.h"<br><br></font><font face=宋体 color=#008000 size=2>//定义删除指针和释放对象的宏</font><font face=宋体 color=#000000 size=2><br><br>#define SAFE_DELETE(p) <br>{ <br>　if(p) <br>　{ <br>　 delete (p); <br>　 (p)=NULL; <br>　 } <br>}<br><br>#define SAFE_RELEASE(p) <br>{ <br>　 if(p) <br>　 { <br>　　 (p)-&gt;Release(); <br>　　 (p)=NULL; <br>　 } <br>}<br><br>#define SCREEN_WIDTH 1024 </font><font face=宋体 color=#008000><font size=2>//定义屏幕宽度</font></font><font face=宋体 color=#000000 size=2><br><br>#define SCREEN_HEIGHT 768 </font><font face=宋体 color=#008000><font size=2>//定义屏幕高度</font></font><font face=宋体 color=#000000 size=2><br><br>#define SCREEN_BPP 8 </font><font face=宋体 color=#008000><font size=2>//定义调色板位数</font></font><font face=宋体 color=#000000 size=2><br><br>#define SPRITE_DIAMETER 32 </font><font face=宋体 color=#008000><font size=2>//定义飘动的子画面 的直径（宽度和高度一样）</font></font><font face=宋体 color=#000000 size=2><br><br>#define NUM_SPRITES 10 </font><font face=宋体 color=#008000><font size=2>//定义飘动的子画面 的个数</font></font><font face=宋体 color=#000000 size=2><br><br>#define HELPTEXT TEXT("Press Escape to quit.") </font><font face=宋体 color=#008000><font size=2>//定义文本住表面</font></font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><font size=2>上面出现的这个 TEXT( ) 是一个系统头文件里定义的宏，起作用是检查程序中是否定义了 Unicode ,如果有，就将括号中的文本转化成宽自负，如果没有，则转化成ASCLL 码。以下定义的是子画面飘动时的属性：</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>struct SPRITE_STRUCT<br><br>{<br>　FLOAT fPosX; </font><font face=宋体 color=#008000><font size=2>//sprite当前坐标的x值,如果在初始化时,即为初始坐标x值</font></font><font face=宋体 color=#000000 size=2><br>　FLOAT fPosY; </font><font face=宋体 color=#008000><font size=2>//sprite当前坐标的y值,如果在初始化时,即为初始坐标y值</font></font><font face=宋体 color=#000000 size=2><br>　FLOAT fVelX; </font><font face=宋体 color=#008000><font size=2>//sprite在x轴上的速度</font></font><font face=宋体 color=#000000 size=2><br>　FLOAT fVelY; </font><font face=宋体 color=#008000><font size=2>//sprite在y轴上的速度</font></font><font face=宋体 color=#000000 size=2><br>};<br><br>CDisplay* g_pDisplay = NULL; </font><font face=宋体 color=#008000><font size=2>/*CDisplay就是ddutil.h（我们又新加入的目录中的）中定义的类，用于处理表面之间的拷贝翻页等操作的类，再次定义一个全局变量，用于以后对指向的表面之间进行操作*/</font></font><font face=宋体 color=#000000 size=2><br><br>CSurface* g_pBackSurface = NULL; </font><font face=宋体 color=#008000><font size=2>/* CSurface也是ddutil.h头文件中定义的类，用于对表面本身进行操作，如设置色彩键码，在此定义的是背景图画指针*/</font></font><font face=宋体 color=#000000 size=2><br><br>CSurface* g_pLogoSurface = NULL; </font><font face=宋体 color=#008000><font size=2>/*子画面图画指针*/</font></font><font face=宋体 color=#000000 size=2><br><br>CSurface* g_pTextSurface = NULL; </font><font face=宋体 color=#008000><font size=2>/*背景文本指针*/</font></font><font face=宋体 color=#000000 size=2><br><br>BOOL g_bActive = FALSE; </font><font face=宋体 color=#008000><font size=2>/*定义一个bool形变量，起到一个开关的作用，对程序流程进行控制*/</font></font><font face=宋体 color=#000000 size=2><br><br>DWORD g_dwLastTick; </font><font face=宋体 color=#008000><font size=2>/*用于记录最后一次的系统时间*/</font></font><font face=宋体 color=#000000 size=2><br><br>SPRITE_STRUCT g_Sprite[NUM_SPRITES]; </font><font face=宋体 color=#008000><font size=2>/*定义多个子画面，其中包括多个 运动时的属性*/</font></font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>Function-prototypes</font></strong></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );</font><font face=宋体 color=#008000 size=2>//主窗口消息处理函数</font><font face=宋体 color=#000000 size=2><br><br>HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel );</font><font face=宋体 color=#008000><font size=2>//窗口类设置，注册，并创建窗口</font></font><font face=宋体 color=#000000 size=2><br><br>HRESULT InitDirectDraw( HWND hWnd );<br><br>VOID FreeDirectDraw();<br><br>HRESULT ProcessNextFrame();<br><br>VOID UpdateSprite( SPRITE_STRUCT* pSprite, FLOAT fTimeDelta );<br><br>HRESULT DisplayFrame();<br><br>HRESULT RestoreSurfaces();</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>WinMain()</font></strong></p>
            <p><font size=2>Desc: Entry point to the program. Initializes everything and calls</font></p>
            <p><font size=2>UpdateFrame() when idle from the message pump.</font></p>
            </font><font face=宋体>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font color=#000000 size=2>int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )<br>{<br>　 MSG msg;<br>　<br>　 HWND hWnd;<br>　<br>　 HACCEL hAccel;<br><br>　 ZeroMemory( &amp;g_Sprite, sizeof(SPRITE_STRUCT) * NUM_SPRITES );</font><font color=#008000 size=2>//清空内存</font><font color=#000000 size=2><br>　<br>　 srand( GetTickCount() </font><font color=#008000 size=2>/*用于获取自windows启动以来经历的时间长度（毫秒）*/</font><font color=#000000 size=2> ); </font><font color=#008000 size=2>//设置随机数随时间变化而变化</font><font color=#000000 size=2><br><br>　 if( FAILED( WinInit( hInst, nCmdShow, &amp;hWnd, &amp;hAccel ) ) )<br>　　 return FALSE;<br><br>　 if( FAILED( InitDirectDraw( hWnd ) ) )<br>　 {<br>　　 MessageBox( hWnd, TEXT("DirectDraw init failed. ")<br>　　<br>　　 TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), <br>　　<br>　　 MB_ICONERROR | MB_OK );<br><br>　　 return FALSE;<br>　 }<br><br>　 g_dwLastTick = timeGetTime();</font><font color=#008000 size=2>//获得当前系统时间</font><font color=#000000 size=2><br><br>　 while( TRUE )<br>　 {<br><br></font><font color=#008000 size=2>// Look for messages, if none are found then <br>// update the state and display it</font><font color=#000000 size=2><br><br>　　 if( PeekMessage( &amp;msg, NULL, 0, 0, PM_NOREMOVE ) )<br>　　 {<br>　　　 if( 0 == GetMessage(&amp;msg, NULL, 0, 0 ) )<br>　　　 {<br><br></font><font color=#008000 size=2>// WM_QUIT was posted, so exit</font><font color=#000000 size=2><br><br>　　　　 return (int)msg.wParam;<br>　　　 }<br><br></font><font color=#008000 size=2>// Translate and dispatch the message</font><font color=#000000 size=2><br><br>　　　 if( 0 == TranslateAccelerator( hWnd, hAccel, &amp;msg ) )<br>　　　 {<br>　　　　 TranslateMessage( &amp;msg ); <br>　　　　 DispatchMessage( &amp;msg );<br>　　　 }<br>　　 }<br>　　 else<br>　　 {<br>　　　 if( g_bActive )<br>　　　 {</font></p>
                        <p class=tabletxt><font color=#008000 size=2>// Move the sprites, blt them to the back buffer, then <br>// flip or blt the back buffer to the primary buffer</font></p>
                        <p class=tabletxt><font color=#000000 size=2>　　　　if( FAILED( ProcessNextFrame() ) </font><font color=#008000 size=2>/*设置下张页面的子画面的位置*/</font><font color=#000000 size=2>)<br>　　　　{<br>　　　　　 SAFE_DELETE( g_pDisplay );<br>　　　　　 <br>　　　　　 MessageBox( hWnd, TEXT("Displaying the next frame failed. ")<br>　　　　　 <br>　　　　　 TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), </font></p>
                        <p class=tabletxt><font color=#000000 size=2>　　　　　 MB_ICONERROR | MB_OK );<br>　　　　　<br>　　　　　 return FALSE;<br>　　　　 }<br>　　　 }<br>　　　 else<br>　　　 {</font></p>
                        <p class=tabletxt><font color=#008000 size=2>// Make sure we go to sleep if we have nothing else to do</font></p>
                        <p class=tabletxt><font color=#000000 size=2>　　　　　WaitMessage();</font></p>
                        <p class=tabletxt><font color=#008000 size=2>// Ignore time spent inactive </font></p>
                        <p class=tabletxt><font color=#000000 size=2>　　　　　g_dwLastTick = timeGetTime();</font><font color=#008000 size=2>//获得当前系统时间</font><font color=#000000 size=2><br>　　　 }<br>　　 }<br>　 }<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </font><font face=Arial>
            <p><strong><font size=2>WinInit()</font></strong></p>
            <p><font size=2>Desc: Init the window</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel ) <br>{<br>　 WNDCLASS wc;<br>　 HWND hWnd;<br>　 HACCEL hAccel;<br><br></font><font face=宋体 color=#008000><font size=2>// Register the Window Class 设置窗口类</font></font><font face=宋体 color=#000000 size=2><br><br>　 wc.lpszClassName = TEXT("FullScreenMode");<br><br>　 wc.lpfnWndProc = MainWndProc;<br><br>　 wc.style = CS_VREDRAW | CS_HREDRAW;<br><br>　 wc.hInstance = hInst;<br><br>　 wc.hIcon = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );<br><br>　 wc.hCursor = LoadCursor( NULL, IDC_ARROW );<br><br>　 wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);<br><br>　 wc.lpszMenuName = NULL;<br><br>　 wc.cbClsExtra = 0;<br><br>　 wc.cbWndExtra = 0;<br><br>　 if( RegisterClass( &amp;wc ) == 0 </font><font face=宋体 color=#008000><font size=2>/*注册窗口类*/</font></font><font face=宋体 color=#000000 size=2> )<br>　　 return E_FAIL;<br><br></font><font face=宋体 color=#008000><font size=2>// Load keyboard accelerators</font></font><font face=宋体 color=#000000 size=2><br><br>　 hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );<br><br></font><font face=宋体 color=#008000><font size=2>// Create and show the main window</font></font><font face=宋体 color=#000000 size=2><br><br>　 hWnd = CreateWindowEx( 0, TEXT("FullScreenMode"), TEXT("DirectDraw FullScreenMode Sample"),<br><br>　 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,<br><br>　 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL );<br><br>　 if( hWnd == NULL )<br>　　 return E_FAIL;<br><br>　 ShowWindow( hWnd, nCmdShow );<br><br>　 UpdateWindow( hWnd );<br><br>　 *phWnd = hWnd;<br><br>　 *phAccel = hAccel;<br><br>　 return S_OK;<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>InitDirectDraw()</font></strong></p>
            <p><font size=2>Desc: Create the DirectDraw object, and init the surfaces</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>HRESULT InitDirectDraw( HWND hWnd )<br>{<br>　 HRESULT hr; </font><font face=宋体 color=#008000><font size=2>//接受返回值，其实是long型变量</font></font><font face=宋体 color=#000000 size=2><br><br>　 LPDIRECTDRAWPALETTE pDDPal = NULL; </font><font face=宋体 color=#008000><font size=2>//定义程序中的调色板</font></font><font face=宋体 color=#000000 size=2><br><br>　 int iSprite; </font><font face=宋体 color=#008000><font size=2>//定义与sprite个数有关的计数器</font></font><font face=宋体 color=#000000 size=2><br><br>　 g_pDisplay = new CDisplay();</font><font face=宋体 color=#008000><font size=2>//动态开辟一个CDisplay类</font></font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = g_pDisplay-&gt;CreateFullScreenDisplay( hWnd, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP ) ) ) </font><font face=宋体 color=#008000><font size=2>//设置程序为全屏，并且g_pDisplay就为后备缓冲区表面的句柄，即指向后备缓冲区表面的指针。</font></font><font face=宋体 color=#000000 size=2><br>　 {<br>　　 MessageBox( hWnd, TEXT("This display card does not support 1024x768x8. "),<br>　　<br>　　 TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );<br>　　<br>　　 return hr;<br>　 }<br><br></font><font face=宋体 color=#008000><font size=2>// Create and set the palette when in palettized color</font></font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = g_pDisplay-&gt;CreatePaletteFromBitmap( &amp;pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) ) </font><font face=宋体 color=#008000><font size=2>//顾名思义，就是从bmp图片中获得调色板值，并赋值在pDDPal结构指针中。</font></font><font face=宋体 color=#000000 size=2><br>　　 return hr;<br>　<br>　 if( FAILED( hr = g_pDisplay-&gt;SetPalette( pDDPal ) ) ) </font><font face=宋体 color=#008000><font size=2>//用刚才从IDB_DIRECTX中获得的调色板制来设置程序调色板</font></font><font face=宋体 color=#000000 size=2><br>　　 return hr;<br><br>　 SAFE_RELEASE( pDDPal );</font><font face=宋体 color=#008000><font size=2>//释放指针</font></font><font face=宋体 color=#000000 size=2><br><br></font><font face=宋体 color=#008000 size=2>// Create a surface, and draw a bitmap resource on it. <br>// 用IDB_DIRECTX图片创建一个表面，并用g_pLogoSurface指向这个表面</font><font face=宋体 color=#000000 size=2><br>　<br>　 if( FAILED( hr = g_pDisplay-&gt;CreateSurfaceFromBitmap( &amp;g_pLogoSurface, MAKEINTRESOURCE( IDB_DIRECTX ), SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )<br>　　 return hr;<br><br>　 if( FAILED( hr = g_pDisplay-&gt;CreateSurfaceFromBitmap( &amp;g_pBackSurface, MAKEINTRESOURCE( IDB_WINXP ), SCREEN_WIDTH, SCREEN_HEIGHT ) ) )<br>　　 return hr;<br><br></font><font face=宋体 color=#008000><font size=2>// Create a surface, and draw text to it. <br>//创建文本表面<br></font></font><font face=宋体 color=#000000 size=2><br>　 if( FAILED( hr = g_pDisplay-&gt;CreateSurfaceFromText( &amp;g_pTextSurface, NULL, HELPTEXT, RGB(0,0,0), RGB(255, 255, 0) ) ) )<br>　　 return hr;<br><br></font><font face=宋体 color=#008000><font size=2>// Set the color key for the logo sprite to black<br>//设置色彩键码为黑色，0代表黑色，这样在表面的拷贝过程中黑色像素的点将不会被拷贝</font></font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = g_pLogoSurface-&gt;SetColorKey( 0 ) ) )<br>　　 return hr;<br><br>　 if( FAILED( hr = g_pTextSurface-&gt;SetColorKey( 0 ) ) )<br>　　 return hr;<br><br></font><font face=宋体 color=#008000><font size=2>// Init all the sprites. All of these sprites look the same, <br>// using the g_pDDSLogo surface. </font></font><font face=宋体 color=#000000 size=2><br><br>　 for( iSprite = 0; iSprite &lt; NUM_SPRITES; iSprite++ )<br>　 {<br><br></font><font face=宋体 color=#008000><font size=2>// Set the sprite's position and velocity<br>// 设置这些 sprite（小怪物）的初始坐标随机产生<br>　</font></font><font face=宋体 color=#000000 size=2><br>　　 g_Sprite[iSprite].fPosX = (float) (rand() % SCREEN_WIDTH);<br>　　 g_Sprite[iSprite].fPosY = (float) (rand() % SCREEN_HEIGHT); <br><br></font><font face=宋体 color=#008000><font size=2>// 速度也随机产生</font></font><font face=宋体 color=#000000 size=2><br><br>　　 g_Sprite[iSprite].fVelX = 500.0f * rand() / RAND_MAX - 250.0f;<br>　　 g_Sprite[iSprite].fVelY = 500.0f * rand() / RAND_MAX - 250.0f;<br>　 }<br>　 return S_OK;<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>FreeDirectDraw()</font></strong></p>
            <p><font size=2>Release all the DirectDraw objects 释放所有指针。</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>VOID FreeDirectDraw()<br>{<br>　 SAFE_DELETE( g_pBackSurface );<br>　 SAFE_DELETE( g_pLogoSurface );<br>　 SAFE_DELETE( g_pTextSurface );<br>　 SAFE_DELETE( g_pDisplay );<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>MainWndProc()</font></strong></p>
            <p><font size=2>Desc: The main window procedure</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )<br>{<br>　 switch (msg)<br>　 {<br>　　 case WM_COMMAND:<br>　　 switch( LOWORD(wParam) )<br>　　 {<br>　　　 case IDM_EXIT:<br><br></font><font face=宋体 color=#008000><font size=2>// Received key/menu command to exit app</font></font><font face=宋体 color=#000000 size=2><br>　<br>　　　 PostMessage( hWnd, WM_CLOSE, 0, 0 );<br>　<br>　　　 return 0L;<br>　　 }<br>　　 break; // Continue with default processing<br><br>　　 case WM_SETCURSOR:<br><br></font><font face=宋体 color=#008000><font size=2>// Hide the cursor in fullscreen </font></font><font face=宋体 color=#000000 size=2><br>　<br>　　 SetCursor( NULL );<br><br>　　 return TRUE;<br><br>　　 case WM_SIZE:<br><br></font><font face=宋体 color=#008000><font size=2>// Check to see if we are losing our window...</font></font><font face=宋体 color=#000000 size=2><br><br>　　 if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )<br>　　　 g_bActive = FALSE;<br>　　 else<br>　　　 g_bActive = TRUE;<br>　　 <br>　　 if( g_pDisplay )<br>　　　 g_pDisplay-&gt;UpdateBounds();<br><br>　　 break；<br><br>　　 case WM_EXITMENULOOP:<br><br></font><font face=宋体 color=#008000><font size=2>// Ignore time spent in menu</font></font><font face=宋体 color=#000000 size=2><br><br>　　 g_dwLastTick = timeGetTime();<br><br>　　 break;<br><br>　　 case WM_EXITSIZEMOVE:<br><br></font><font face=宋体 color=#008000 size=2>// Ignore time spent resizing</font><font face=宋体 color=#000000 size=2><br><br>　　 g_dwLastTick = timeGetTime();<br><br>　　 break;<br><br>　　 case WM_MOVE:<br><br>　　 if( g_pDisplay )<br>　　　 g_pDisplay-&gt;UpdateBounds();<br><br>　　 break;<br><br>　　 case WM_SYSCOMMAND:<br><br></font><font face=宋体 color=#008000><font size=2>// Prevent moving/sizing and power loss in fullscreen mode</font></font><font face=宋体 color=#000000 size=2><br><br>　　 switch( wParam )<br>　　 {<br>　　　 case SC_MOVE:<br><br>　　　 case SC_SIZE:<br><br>　　　 case SC_MAXIMIZE:<br><br>　　　 case SC_MONITORPOWER:<br><br>　　　 return TRUE;<br>　　 }<br><br>　　 break;<br><br>　　 case WM_DESTROY:<br><br></font><font face=宋体 color=#008000><font size=2>// Cleanup and close the app</font></font><font face=宋体 color=#000000 size=2><br><br>　　 FreeDirectDraw();<br><br>　　 PostQuitMessage( 0 );<br><br>　　 return 0L;<br>　 }<br>　<br>　 return DefWindowProc(hWnd, msg, wParam, lParam);<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>ProcessNextFrame()</font></strong></p>
            <p><font size=2>Desc: Move the sprites, blt them to the back buffer, then </font></p>
            <p><font size=2>flips the back buffer to the primary buffer</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>HRESULT ProcessNextFrame()<br>{<br>　 HRESULT hr;<br><br></font><font face=宋体 color=#008000><font size=2>// Figure how much time has passed since the last time</font></font><font face=宋体 color=#000000 size=2><br><br>　 DWORD dwCurrTick = timeGetTime(); </font><font face=宋体 color=#008000><font size=2>//get current time 获得当前时间</font></font><font face=宋体 color=#000000 size=2><br>　 DWORD dwTickDiff = dwCurrTick - g_dwLastTick; </font><font face=宋体 color=#008000><font size=2>//the difference between current-time (dwCurrTick) and last time (g_dwLastTick)</font></font><font face=宋体 color=#000000 size=2><br><br></font><font face=宋体 color=#008000 size=2>//计算当前时间 (dwCurrTick) 与最后一次时间 (g_dwLastTick) 的差值<br>// Don't update if no time has passed </font><font face=宋体 color=#000000 size=2><br><br>　 if( dwTickDiff == 0 ) </font><font face=宋体 color=#008000><font size=2>//如果时间差值为0,即时间没有变化,则不更新屏幕,而返回</font></font><font face=宋体 color=#000000 size=2><br>　　 return S_OK; <br><br></font><font face=宋体 color=#008000><font size=2>//如果程序运行到这里,而没有在前面返回,则说明时间有变化,则下面将要更新屏幕</font></font><font face=宋体 color=#000000 size=2><br><br>　 g_dwLastTick = dwCurrTick; </font><font face=宋体 color=#008000><font size=2>//使最后时间=当前时间</font></font><font face=宋体 color=#000000 size=2><br><br></font><font face=宋体 color=#008000 size=2>// Move the sprites according to how much time has passed<br>//根据时间的变化来移动子画面,即移动sprites<br></font><font face=宋体 color=#000000 size=2><br>　 for( int iSprite = 0; iSprite &lt; NUM_SPRITES; iSprite++ )<br>　　 UpdateSprite( &amp;g_Sprite[ iSprite ], dwTickDiff / 1000.0f );<br><br></font><font face=宋体 color=#008000><font size=2>// Display the sprites on the screen</font></font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = DisplayFrame() ) )<br>　 {<br>　　 if( hr != DDERR_SURFACELOST )<br>　　　 return hr;<br><br></font><font face=宋体 color=#008000><font size=2>// The surfaces were lost so restore them </font></font><font face=宋体 color=#000000 size=2><br><br>　　 RestoreSurfaces();<br>　 }<br><br>　 return S_OK;<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>UpdateSprite()</font></strong></p>
            <p><font size=2>Desc: Move the sprite around and make it bounce based on how much time has passed ，此函数属于动画的关键算法，就是控制spirte如何移动</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>VOID UpdateSprite( SPRITE_STRUCT* pSprite, FLOAT fTimeDelta )<br>{ <br><br></font><font face=宋体 color=#008000><font size=2>// Update the sprite position</font></font><font face=宋体 color=#000000 size=2><br><br>　 pSprite-&gt;fPosX += pSprite-&gt;fVelX * fTimeDelta;<br>　 pSprite-&gt;fPosY += pSprite-&gt;fVelY * fTimeDelta;<br><br></font><font face=宋体 color=#008000><font size=2>// Clip the position, and bounce if it hits the edge</font></font><font face=宋体 color=#000000 size=2><br><br>　 if( pSprite-&gt;fPosX &lt; 0.0f )<br>　 {<br>　　 pSprite-&gt;fPosX = 0;<br>　　 pSprite-&gt;fVelX = -pSprite-&gt;fVelX;<br>　 }<br>　 <br>　 if( pSprite-&gt;fPosX &gt;= SCREEN_WIDTH - SPRITE_DIAMETER )<br>　 {<br>　　 pSprite-&gt;fPosX = SCREEN_WIDTH - 1 - SPRITE_DIAMETER;<br>　　 pSprite-&gt;fVelX = -pSprite-&gt;fVelX;<br>　 }<br>　<br>　 if( pSprite-&gt;fPosY &lt; 0 )<br>　 {<br>　　 pSprite-&gt;fPosY = 0;<br>　　 pSprite-&gt;fVelY = -pSprite-&gt;fVelY;<br>　 }<br><br>　 if( pSprite-&gt;fPosY &gt; SCREEN_HEIGHT - SPRITE_DIAMETER )<br>　 {<br>　　 pSprite-&gt;fPosY = SCREEN_HEIGHT - 1 - SPRITE_DIAMETER;<br>　　 pSprite-&gt;fVelY = -pSprite-&gt;fVelY;<br>　 } <br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>DisplayFrame()</font></strong></p>
            <p><font size=2>Desc: Blts a the sprites to the back buffer, then flips the back buffer onto the primary buffer.</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>HRESULT DisplayFrame()<br>{<br>　 HRESULT hr;<br><br></font><font face=宋体 color=#008000><font size=2>// Fill the back buffer with black, ignoring errors until the flip</font></font><font face=宋体 color=#000000 size=2><br><br>　 g_pDisplay-&gt;Clear( 0 ); </font><font face=宋体 color=#008000><font size=2>//清空后备缓冲区表面</font></font><font face=宋体 color=#000000 size=2><br><br></font><font face=宋体 color=#008000><font size=2>// Blt the help text on the backbuffer, ignoring errors until the flip<br>//将g_pBackSurface所指向的图片拷贝到后备缓冲区表面</font></font><font face=宋体 color=#000000 size=2><br><br>　 g_pDisplay-&gt;Blt( 0, 0, g_pBackSurface, NULL );<br><br></font><font face=宋体 color=#008000><font size=2>//将g_pTextSurface所指向的文本拷贝到后备缓冲区表面</font></font><font face=宋体 color=#000000 size=2><br><br>　 g_pDisplay-&gt;Blt( 10, 10, g_pTextSurface, NULL );<br><br></font><font face=宋体 color=#008000><font size=2>// Blt all the sprites onto the back buffer using color keying,<br>// ignoring errors until the flip. Note that all of these sprites <br>// use the same DirectDraw surface.<br>//将所有的spirits拷贝到后备缓冲区表面，这里要注意拷贝顺序，后拷贝上的画面会压盖在先拷贝的画面上</font></font><font face=宋体 color=#000000 size=2><br><br>　 for( int iSprite = 0; iSprite &lt; NUM_SPRITES; iSprite++ )<br>　 {<br>　　 g_pDisplay-&gt;Blt( (DWORD)g_Sprite[iSprite].fPosX,(DWORD)g_Sprite[iSprite].fPosY,g_pLogoSurface, NULL );<br>　 }<br><br></font><font face=宋体 color=#008000><font size=2>// We are in fullscreen mode, so perform a flip and return <br>// any errors like DDERR_SURFACELOST<br>//最关键的地方在这里，请看下面的语句，只要我们一执行翻页操作，就可以将改动了的图像了显示在屏幕上了</font></font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = g_pDisplay-&gt;Present() </font><font face=宋体 color=#008000 size=2>/*翻页操作*/</font><font face=宋体 color=#000000 size=2>) )<br>　　 return hr;<br><br>　 return S_OK;<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><strong><font size=2>RestoreSurfaces()</font></strong></p>
            <p><font size=2>Desc: Restore all the surfaces, and redraw the sprite surfaces.</font></p>
            </font>
            <table class=code cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font face=宋体 color=#000000 size=2>HRESULT RestoreSurfaces()<br>{<br>　 HRESULT hr;<br><br>　 LPDIRECTDRAWPALETTE pDDPal = NULL; <br><br>　 if( FAILED( hr = g_pDisplay-&gt;GetDirectDraw()-&gt;RestoreAllSurfaces() ) )<br>　　 return hr;<br><br></font><font face=宋体 color=#008000 size=2>// No need to re-create the surface, just re-draw it.</font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = g_pTextSurface-&gt;DrawText( NULL, HELPTEXT, 0, 0, RGB(0,0,0), RGB(255, 255, 0) ) ) )<br>　　 return hr;<br><br></font><font face=宋体 color=#008000 size=2>// We need to release and re-load, and set the palette again to <br>// redraw the bitmap on the surface. Otherwise, GDI will not <br>// draw the bitmap on the surface with the right palette</font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = g_pDisplay-&gt;CreatePaletteFromBitmap( &amp;pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )<br>　　 return hr;<br><br>　 if( FAILED( hr = g_pDisplay-&gt;SetPalette( pDDPal ) ) )<br>　　 return hr;<br><br>　 SAFE_RELEASE( pDDPal );<br><br></font><font face=宋体 color=#008000 size=2>// No need to re-create the surface, just re-draw it.</font><font face=宋体 color=#000000 size=2><br><br>　 if( FAILED( hr = g_pLogoSurface-&gt;DrawBitmap( MAKEINTRESOURCE( IDB_DIRECTX ),SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )<br>　　 return hr;<br>　 return S_OK;<br>}</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <font face=Arial>
            <p><font size=2>好了，我们的程序分析就到这了，我想您现在应该大概了解了DirectDraw程序的大概流程了吧，就是先创建DDraw对象，然后进行相关的设置，然后绘制后备缓冲区页，然后执行翻页操作，这样循环，就会产生很好的动画效果了，其实用DirectDraw编程很简单，说白了其实就是：&#8220;几个表面之间拷来拷去&#8221;。只不过这其间可是大有文章可作的哟！</font></p>
            </font></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86484.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:26 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86484.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动画程序编写——DirectDraw之旅（2）</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86483.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:25:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86483.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86483.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86483.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86483.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86483.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2.htm">http://dev.gameres.com/Program/Visual/2D/DDrawZL_2.htm</a><br><br>
<table id=AutoNumber2 style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width="85%" border=0>
    <tbody>
        <tr>
            <td width="100%">
            <p align=center><font color=#ffffee><strong>动画程序编写——DirectDraw之旅（2）</strong></font></p>
            </td>
        </tr>
        <tr>
            <td width="100%">　</td>
        </tr>
        <tr>
            <td width="100%"><font size=2>&#8220;君欲善其事，必先利其器&#8221;，在编写DirectDraw应用程序之前，我们先要准备好以下工具：</font>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=tabletxt><font size=2>Windows95、Windows98、Windows Me、Windows NT 4.0、Windows 2000 或 Windows XP（其对操作系统没有特殊要求）</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt><font size=2>DirectX 驱动程序(最好是DirectX 8.0以上版本)</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt><font size=2>DirectX 8.0 SDK </font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt><font size=2>Visual C＋＋ 5.0 ，Visual C＋＋ 6.0 或 Visual C＋＋ .NET</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size=2>Direct SDK包括开发基于DirectX应用程序所需的全部文件，全部安装需要80兆的硬盘空间。其实你只需安装必需的头文文件（.h文件）和库文件（.lib文件）就行了。</font></p>
            <p><font size=2>安装完DirectX SDK，需要通知Visual C＋＋ DirectX SDK的路径。具体做法是：在VC的编译环境中，依次把Tools－Options－Directories中的Show Directories for一栏中的include files和library files中分别填入SDK的include和lib目录，如图所示。</font></p>
            <p><font size=2><img height=280 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_1.gif" width=492></font></p>
            <p><font size=2><img height=419 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_2.gif" width=531></font></p>
            <p><font size=2><img height=422 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_3.gif" width=545></font></p>
            <p><font size=2>再准备两幅bmp格式的位图，其中winXP.bmp作背景，如图；另一幅directx.bmp作为子画面，如图。还要注意一点的是子画面的背景要为黑色(RGB=(0,0,0))，因为在下面的程序中，色彩键码把黑色设为透明色。</font></p>
            <p><font size=2><img height=339 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_4.jpg" width=453></font></p>
            <p><font color=#000000 size=2>winXP.bmp 1024&#215;768&#215;24</font></p>
            <p><font size=2><img height=32 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_5.jpg" width=32></font></p>
            <p><font color=#000000 size=2>directx.bmp 32&#215;32&#215;8</font></p>
            <p><font size=2>进入VC6的编程环境，File－New－Project,选择Win32 Application,输入项目名FullScreenMode ,按下Ok,以后每一步都按其缺省值即可，这样AppWizard就会自动创建一个空项目，下面我们还需要加入一个cpp源文件，并将Win32程序的基本框架拷贝入刚刚创建的cpp源文件中。如下图1、2：</font></p>
            <p><font size=2><img height=479 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_6.gif" width=463></font></p>
            <p><font size=2><img height=479 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_7.gif" width=278></font></p>
            <p><font size=2>然后点击&#8220;文件&#8221;选项卡添加.CPP工程文件。如下图3：</font></p>
            <p><font size=2><img height=391 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_8.gif" width=541></font></p>
            <p><font size=2>其实我们的工程中还要用到DirectX SKD提供的四个文件：</font></p>
            <table cellSpacing=1 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=tabletxt><font size=2>ddutil.h </font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt><font size=2>ddutil.cpp </font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt><font size=2>dxutil.h</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt><font size=2>dxutil.cpp</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size=2>对于头文件，我们还采用上面添加编译器默认头文件目录的方法让编译器自己去找，如图：</font></p>
            <p><font size=2><img height=417 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_9.gif" width=523></font></p>
            <p><font size=2>上面的目录是我们刚才加入的，而下面的目录是我们这次加入的。而对于 cpp源文件，我们采用将文件直接导入工程的方法，如图：</font></p>
            <p><font size=2><img height=373 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_10.gif" width=379></font></p>
            <p><font size=2><img height=218 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_11.gif" width=346><br><br>文件 ddutil.cpp dxutil.cpp 所在目录为 </font></p>
            <table cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0>
                <tbody>
                    <tr>
                        <td class=tabletxt width="8%" bgColor=#e0e0e0><font size=2>（9.0版本）</font></td>
                        <td class=tabletxt width="92%" bgColor=#ffffff><font size=2>C:\DXSDK\Samples\C++\Common\Src</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt bgColor=#e0e0e0><font size=2>（8.0版本） </font></td>
                        <td class=tabletxt bgColor=#ffffff><font size=2>C:\DXSDK \samples\multimedia\common\src</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size=2>所有的工程文件结构如图：</font></p>
            <p><font size=2><img height=270 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_12.gif" width=306></font></p>
            <p><font size=2>下面的所有程序都是 FullScreenMode.cpp 文件中的内容，其中IDB_DIRECTX和IDB_WinXP都是图片资源的ID号，向程序中添加资源的过程如图：</font></p>
            <p><font size=2><img height=480 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_13.gif" width=546> </font></p>
            <p><font size=2><img height=303 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_14.gif" width=541></font></p>
            <p><font size=2><img height=334 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_2_15.gif" width=467></font></p>
            <p><font size=2>其它的资源文件也是这样加入的。请读者自己将图片加入到程序中。</font></p>
            </td>
        </tr>
        <tr>
            <td width="100%">　</td>
        </tr>
        <tr>
            <td width="100%" bgColor=#151631>
            <p align=right><font face=Arial color=#0000ff size=1><a href="http://www.frontfree.net/"><u>放飞技术网</u></a></font><font size=1>&nbsp;&nbsp;</font></p>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86483.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:25 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86483.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动画程序编写——DirectDraw之旅（1）</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86481.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 15:23:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86481.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86481.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86481.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86481.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86481.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DDrawZL_1.htm">http://dev.gameres.com/Program/Visual/2D/DDrawZL_1.htm</a><br><br>
<table id=AutoNumber2 style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width="85%" border=0>
    <tbody>
        <tr>
            <td width="100%">
            <p align=center><font color=#ffffee><strong>动画程序编写——DirectDraw之旅（1）</strong></font></p>
            </td>
        </tr>
        <tr>
            <td width="100%">　</td>
        </tr>
        <tr>
            <td width="100%"><font size=2>DirectDraw——也许大多数人闻所未闻，但当提到 DirectX 恐怕每一个 游戏爱好者都再熟悉不过了,但是只知道那是一个很多游戏都要求的必须安装的程序,再多就无从所知了,那么它到底能为我们的游戏干什么呢,其实它又叫 Game SDK，它最大的特点是直接对硬件的抽象层(HAL)进行操作，利用 此特点可制作出高性能的Windows游戏。<br>http://www. microsoft.com/directx/default.asp。 </font>
            <p><font size=2>DirectDraw就是DirectX5的6个组件之一。DirectX5的其它5个组件分别是：</font></p>
            <table cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0>
                <tbody>
                    <tr>
                        <td class=tabletxt width="8%" bgColor=#e0e0e0><font color=#000000 size=2>Direct3D</font></td>
                        <td class=tabletxt width="92%" bgColor=#ffffff><font color=#000000 size=2>提供了3D硬件接口。</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt bgColor=#e0e0e0><font color=#000000 size=2>DirectSound</font></td>
                        <td class=tabletxt bgColor=#ffffff><font color=#000000 size=2>立体声和3D声音效果，同时管理声卡的内存。</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt bgColor=#e0e0e0><font color=#000000 size=2>DirectPlay</font></td>
                        <td class=tabletxt bgColor=#ffffff><font color=#000000 size=2>支持开发多人网络游戏，并能处理游戏中网络之间的通信问题。</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt bgColor=#e0e0e0><font color=#000000 size=2>DirectInput</font></td>
                        <td class=tabletxt bgColor=#ffffff><font color=#000000 size=2>为大量的设备提供输入支持。</font></td>
                    </tr>
                    <tr>
                        <td class=tabletxt bgColor=#e0e0e0><font color=#000000 size=2>DirectSetup</font></td>
                        <td class=tabletxt bgColor=#ffffff><font color=#000000 size=2>自动安装DirectX驱动程序。</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size=2>而DirectDraw则是DirectX的基础，DirectX的其它组件都是建立在它的基础之上的。DirectDraw使用页面切换的方法实现动画，它不仅可以访问系统内存，还可以访问显示内存，这是以往的Windows程序员所不能的。(例如:如果你是用MFC中的CDC类进行绘图,那么它是绝对不会让您直接访问显存的。) 另外，我们利用DirectDraw还可以生成、移动、剪切、转换、合成图像数据，从而编写出各种&#8220;炫丽多彩&#8221;图形的应用程序。</font></p>
            <p><font size=2>您先不要急,我们会在后面附上本文介绍的动画程序原代码,只要将其用vc打开,进行工程的编译创建后,您就会立刻看到效果。并且我们在工程文件中有详细的中文注释,力求将理论与实践紧密联系在一起。</font></p>
            <p><font size=2>首先，让我们先了解一下DirectDraw的三个重要概念</font><font color=#000000><font size=2>——</font><font color=#ff0000 size=2>表面、Bltting、色彩键码</font></font></p>
            <p class=titletxt><font color=#0099ff size=2><strong>1.表面</strong></font></p>
            <p><font size=2>在用DirectDraw编写程序时,我们先要创建若干个图形数据缓冲区，并把这些图形数据装入其中，再进行转换、拉伸、挎贝等操作，并且还可以显示这些缓冲区中的图形数据，这些缓冲区就称为表面。</font></p>
            <p><font size=2>表面可以分为几类。</font></p>
            <p><font color=#0099ff size=2>主表面</font><font size=2>(primary surface)是用户在屏幕上可以看到的，它是显示内存的一部分。所有DirectDraw程序都有主表面，而且只有一个。它在DirectDraw表面对象之前就已经存在了，因此不能改变它的尺寸、格式和位置。</font></p>
            <p><font size=2>主表面有一个很重要的特性——翻页(flip)。页面翻页用于程序中，可以产生相当平滑、不闪烁的动画。一个可以翻页的主表面实际上是两个表面，一个是可见的，一个是不可见的。不可见的表面称为<font color=#0099ff>后备缓冲区</font>。当发生表面翻页时，后备缓冲区就成为可见的，而以前的可见主表面则成为后备缓冲区。 下面我们用图示来向您解释上面的概念:</font></p>
            <p><font size=2><img height=133 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_1_1.gif" width=468><br><br>当翻页后,将原后备缓冲区页中的内容copy入可见主表面页,而同时将原可见主表面页的内容copy入后备缓冲区页。 </font></p>
            <p><font size=2>显示器屏幕虽然每秒中刷新很多次，在此我们假定为85次，但每次都是一遍一遍地读取可见主表面中存储的显示页信息，而你对后备缓冲区的改动不会显示出来，并且也不会影响可见主表面的显示，而只有当施行翻页操作后，两页的内容互换，而你已经完成了的在原后备缓冲区的改动才会显示在屏幕上，而这个互相拷贝的过程几乎是瞬间完成的，这个时间比起每次刷新所用的时间少得多得多，两者几乎差了几乎几十万个数量级。而人眼是根本察觉不到的，所以用这种方法可以不闪烁，平滑，优质的动画效果</font></p>
            <p><font size=2>还有一种表面叫<font color=#0099ff>离屏表面</font>(off_screen surface)，它是不能直接见到的。离屏表面作为存储缓冲区，有助于表面之间的互相切换，它的大小是可以改变的。</font></p>
            <p><font size=2>主表面和离屏表面都分为有调色板的和无调色板的这两类。像素深度为8位(256色)的表面称为有调色板的表面；而像素深度为16位(64K色)、24位(16M色)的像素表面称为无调色板的表面，它们存储实际的色彩值(RGB值)。</font></p>
            <p><font size=2>在本文下面的程序中，我们先使用256位表面即有调色板的表面。</font></p>
            <p><font color=#0099ff size=2><strong>2. Bltting</strong></font></p>
            <p><font size=2>Bltting是用于复制图形的语言，可以将图像从一处拷贝到另一处。例如大家所熟悉的<font color=#0099ff>CDC类</font>(设备描述表类)的BitBlt()就是具有这样功能的函数。</font></p>
            <p><font size=2>在DirectDraw中，典型的blt操作是将离屏表面的内容拷贝到一个后备缓冲区，而一般的blt操作调用一个源表面和一个目标表面，把源表面的内容拷贝到目标表面中，不仅可以整体拷贝源表面，而且还可以拷贝源表面内的任何矩形区域到目标表面的任何位置。blt还支持透明拷贝，就是指表面中的某一像素在blt过程中可以不予以拷贝，而这个像素值是由<font color=#0099ff>色彩键码</font>(DDCOLOR KEY )决定的。如图：</font></p>
            <p><font size=2><img height=177 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_1_2.gif" width=430></font></p>
            <p><font size=2>DirectDraw中有三个支持blt的函数，它们是</font></p>
            <table cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td bgColor=#e0e0e0>
                        <p class=tabletxt><font color=#000000 size=2>Blt()<br>BltBatch()<br>BltFast()</font></p>
                        </td>
                    </tr>
                </tbody>
            </table>
            <p><font size=2>Blt( )用得最多，BltFast()的速度比Blt()要快，但功能却很有限，例如不支持拉伸、剪切等操作。</font></p>
            <p><font size=2>还有一个函数BltSurface()，它是DirectWin类的一个成员函数，Blt()、BltFast()更具有适应性，并且使用起来更加简单。例如，当我们把源表面拷贝到目标表面外时需要裁剪，而BltFast()不支持裁剪。这时我们使用BltSurface()函数，它在内部使用Blt()和 BltSurface()函数，并根据情况自动执行裁剪。</font></p>
            <p><font size=2>在此，有人会问，这种页面切换的方法到底好在那里？它到底与用一般的绘图方法的区别在什么地方？而其它的绘图方法为什么会使屏幕闪动呢？下面我们举二个例子：</font><font color=#000000 size=2>（我们仍然用图示的方法给您一个直观的解释）</font></p>
            <p><font size=2>（1） 在一些绘图程序中您会发现其用到了清屏函数，这种方式是使屏幕效果最差的，这种方法使得没有直接从第一个画面切换到第二个画面，而是先用黑色将图形数据缓冲区清空，并且还显示在屏幕上，但这个时间很短。如果反复清屏，则会产生严重的屏幕闪烁。如下图：<br>　</font></p>
            <p><font size=2><img height=157 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_1_3.gif" width=532></font></p>
            <p><font size=2>（2）在一些程序中用异或的方式进行绘图，即先在屏幕上画出第一个图像，然后在画第二个图像之前，再在屏幕上画一遍第一个图像，这样起到清除第一个图像的效果。如果您仔细看，会发现这样就会比上一个方法的画面效果好得多，但这并不是很完美，因为如果反复使用，虽然不会产生全屏幕的闪动，但在所清除图像处会产生闪烁。究其根本原因还是因其没能直接从第一个画面切换到第二个画面。如下图：</font></p>
            <p><font size=2><img height=204 src="http://dev.gameres.com/Program/Visual/2D/DDrawZL_1_4.gif" width=458></font></p>
            <p><font size=2>我想现在您应明白DirectDraw绘图的优势了吧，其实这就是对上述方法中缺点的很好的解决方法。<br><br></font><strong><font color=#0099ff size=2>3.色彩键码</font></strong></p>
            <p><font size=2>DirectDraw 可以把某种颜色或某个范围的颜色指定为一个颜色值，这个颜色值是由DDCOLORKEY结构即色彩键码说明的，DDCORLORKEY结构说明如下：</font></p>
            <table cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=tabletxt bgColor=#e0e0e0><font color=#000000 size=2>typedef struct _DDCOLORKEY<br>{ <br>　DWORD dwColorSpaceLowValue; //颜色范围的低端<br>　DWORD dwColorSpaceHighValue; //颜色范围的高端<br>} DDCOLORKEY;</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size=2>当我们对表面进行拷贝操作时,表面中哪些像素不被拷贝是由色彩键码决定的。例如当DDCOLORKEY结构的两个分量都为零时，表面内所有置为零的像素都不能被拷贝。又例如，当表面是24位RGB模式时，若想指定RGB=(120，120，120)像素不被拷贝，则应该:</font></p>
            <table cellSpacing=4 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td class=tabletxt bgColor=#e0e0e0><font color=#000000 size=2>DDCOLORKEY ddck;<br>ddck.dwColorSpaceLowValue=RGB(120,120,120);<br>ddck.dwColorSpaceHighValue=RGB(120,120,120);<br>surf&#8594;SetColorKey(DDCKEY_SRCBLT,＆ddck);</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size=2>其中SetColorKey()函数是把色彩键码赋给表面surf。这样，在对表面surf的 blt操作期间RGB值为(120,120,120)的像素不能被拷贝。</font></p>
            <p><font size=2>OK，我们现在已经具备基本的DirectDraw的知识，下面我们就来进行实战演练（未完待续......）</font></p>
            </td>
        </tr>
        <tr>
            <td width="100%">　</td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/86481.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 23:23 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86481.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从头学习DirectDraw</title><link>http://www.cppblog.com/iniwf/archive/2009/06/01/86476.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 01 Jun 2009 14:58:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/06/01/86476.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/86476.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/06/01/86476.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/86476.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/86476.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>http:</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">dev.gameres.com/Program/Visual/2D/fromfirst.htm</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>从头学习DirectDraw<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　在开始学习DirectDraw编程之前，有一些题外话要说明，以下内容均是个人的心得和体会，如果其中有什么谬误之处，敬请谅解，同时个人不对可能造成的后果负责。。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　以下几点是在编制DirectX应用程序时应该注意的：&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>尽管使用VB或DELPHI都可以制作DirectX应用程序，但考虑到代码的效率，还是应使用C或C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">。其中，C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">是面向对象的编程语言，可以使你的程序更易于维护，如果再考虑到代码的兼容性，我推荐使用Microsoft&nbsp;Visual&nbsp;C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.0集成开发环境。当然，使用Borland&nbsp;C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.0也是一个不错的选择。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>你应该已经有编制Windows应用程序的经验，以及C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">的基础。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>熟悉你将要使用的编程工具的运用。例如，如何为集成开发环境设置各种参数，以及编译程序和连接程序的命令行参数。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>确认你已下载了微软的DirectX&nbsp;</span><span style="COLOR: #000000">5.0</span><span style="COLOR: #000000">&nbsp;SDK中的相关文件，特别是头文件和库文件，这些都是编程所必需的。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>确认你已经安装了DirectX&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.0或更高版本的运行时刻库，因为本教程的所有程序均使用了DirectX的新接口（Interface），必须要5.0或更高版本支持。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">--------------------------------------------------------------------------------</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>DirectDraw是什么？<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　DirectDraw是DirectX中的关于视频输入输出的基本部分，使用DirectDraw可以方便地编制出高效的视频处理程序，只要用户的硬件支持DirectDraw，就能保证你的代码可以处理它们。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　简单地说，一个DOS程序员可以方便地直接访问视频显存，从而高效地处理视频动画，而在Windows的32位环境中，使用DirectDraw可以做类似的工作（而且做得更好）。例如，在DOS环境中的320x200x256色图形模式中，你可以通过在地址A000:0000开始处的一片内存区进行直接读写的方式来处理视频操作，而在Windows环境中，DirectDraw也提供一片内存区供你直接读写，使你能更好地完成相似的操作。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　当然，DirectDraw提供的远不止这些，但一个游戏程序员可能更关心如何直接访问视频显存，以及如何高效地完成位块拷贝操作等等。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">--------------------------------------------------------------------------------</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>让我们从消息循环开始<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　DirectX最初是为游戏开发而推出的，编制游戏的程序员都很贪婪，他们会尽量榨取系统资源，并试图让自己的程序永远具有最高的效率。但Windows是一个多任务的操作系统，当它发现所有的程序都处于空闲时，便会减少给这些程序的资源，其中之一就是开始清理交换文件，为了让自己的程序给Windows以始终繁忙的假象，不妨用一些新的代码来代替常规的方法。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>这是常规的消息循环处理<br><img id=Codehighlighter1_1432_1625_Open_Image onclick="this.style.display='none'; Codehighlighter1_1432_1625_Open_Text.style.display='none'; Codehighlighter1_1432_1625_Closed_Image.style.display='inline'; Codehighlighter1_1432_1625_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1432_1625_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1432_1625_Closed_Text.style.display='none'; Codehighlighter1_1432_1625_Open_Image.style.display='inline'; Codehighlighter1_1432_1625_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(GetMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg,NULL,NULL,NULL))</span><span id=Codehighlighter1_1432_1625_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1432_1625_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TranslateMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;msg.wParam;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这是改进的消息循环处理<br><img id=Codehighlighter1_1875_2655_Open_Image onclick="this.style.display='none'; Codehighlighter1_1875_2655_Open_Text.style.display='none'; Codehighlighter1_1875_2655_Closed_Image.style.display='inline'; Codehighlighter1_1875_2655_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1875_2655_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1875_2655_Closed_Text.style.display='none'; Codehighlighter1_1875_2655_Open_Image.style.display='inline'; Codehighlighter1_1875_2655_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(;;)</span><span id=Codehighlighter1_1875_2655_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1875_2655_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_1971_2243_Open_Image onclick="this.style.display='none'; Codehighlighter1_1971_2243_Open_Text.style.display='none'; Codehighlighter1_1971_2243_Closed_Image.style.display='inline'; Codehighlighter1_1971_2243_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1971_2243_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1971_2243_Closed_Text.style.display='none'; Codehighlighter1_1971_2243_Open_Image.style.display='inline'; Codehighlighter1_1971_2243_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(PeekMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg,NULL,NULL,NULL,PM_REMOVE))</span><span id=Codehighlighter1_1971_2243_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1971_2243_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(msg.message</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">WM_QUIT)&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TranslateMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg)<br><img id=Codehighlighter1_2248_2605_Open_Image onclick="this.style.display='none'; Codehighlighter1_2248_2605_Open_Text.style.display='none'; Codehighlighter1_2248_2605_Closed_Image.style.display='inline'; Codehighlighter1_2248_2605_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_2248_2605_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2248_2605_Closed_Text.style.display='none'; Codehighlighter1_2248_2605_Open_Image.style.display='inline'; Codehighlighter1_2248_2605_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #0000ff">else</span><span id=Codehighlighter1_2248_2605_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2248_2605_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(AppPaused)&nbsp;WaitMessage();<br><img id=Codehighlighter1_2379_2555_Open_Image onclick="this.style.display='none'; Codehighlighter1_2379_2555_Open_Text.style.display='none'; Codehighlighter1_2379_2555_Closed_Image.style.display='inline'; Codehighlighter1_2379_2555_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_2379_2555_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2379_2555_Closed_Text.style.display='none'; Codehighlighter1_2379_2555_Open_Image.style.display='inline'; Codehighlighter1_2379_2555_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span id=Codehighlighter1_2379_2555_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2379_2555_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;这里进行任何不基于消息循环的处理<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;例如动画制作</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;msg.wParam;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　上例中，新的消息循环处理方式使得Windows认为程序始终繁忙，从而提高了程序的性能。注意，其中的AppPaused变量为真时表示程序未在前台运行，该变量的取值为WM_ACTIVATEAPP消息的wParam参数。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">--------------------------------------------------------------------------------</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>第一个DirectDraw程序<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　现在咱们开始编制第一个DirectDraw的应用程序，来示例如何建立一个全屏幕独占方式的应用程序，并利用HDC来实现简单的文本输出。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　这个示例与微软的示例程序不同，它使用了DirectX&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.0中的新接口，在制作最终可执行程序时应确保为LINK程序指定ddraw.lib和dxguid.lib这两个文件。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　示例程序的可执行程序由VC&nbsp;</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.0生成，只在基于Intel奔腾芯片、Windows95环境的机器上才能运行。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　下面重点介绍一下建立和销毁DirectDraw基本对象的方法，以及如何请求新接口。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>首先来说明一下以后要用到的术语：&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>DirectDraw基本对象。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>这个对象的实体由DirectX建立，程序只能通过指向该对象实体的指针来访问它，这一点与Delphi十分相似，在Delphi中，一个TLabel类型的变量实际只是一个指针，它指向一个TLabel类的对象。建立DirectDraw基本对象的函数是DirectDrawCreate()，该函数可在内部建立一个DirectDraw对象实体，并将指向该实体的指针返回给应用程序，以后的所有操作都基于这个指针。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>主平面。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>可以将主平面简单地理解为&#8220;视频显存区&#8221;，任何直接对主平面的访问都立刻反映到屏幕上。主平面也是一个对象（程序员只能使用指向该对象的指针），该对象封装了几乎所有的输入输出操作，包括直接访问、利用设备相关（DC）访问以及位块拷贝（Blt）操作等等。主平面可以附带一个或多个&#8220;后台缓冲区&#8221;。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>后台缓冲区。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>后台缓冲区同样也是一个对象，也同样只提供一个指向该对象的指针供程序员使用。后台缓冲区与主平面的操作方式几乎一样，不同的是所有对后台缓冲区的操作不直接反映在屏幕上，例如，你可以在后台缓冲区中放置好图片，然后通过位块拷贝操作（或&#8220;弹出&#8221;操作）将后台缓冲区中的内容快速映射到主平面（即屏幕），这种操作方式可以避免出现不愉快的闪烁现象。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>位块拷贝。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>位块拷贝是将一块矩形区域从一个平面拷贝到另一个平面，可以进行缩放、旋转、镜像、透明等附加动作。DirectDraw提供的位块拷贝方法效率十分高，程序员勿需自行编制代码来完成相似工作。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&#8220;弹出&#8221;操作。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Flip这个单词有反转、弹出等含义，在DirectDraw中，可以将其理解为迅速互换两个平面，这种互换操作并不是内容的互换，而只是指针的互换，因此其速度比位块拷贝快得多。例如，在全屏幕独占方式下，可以利用&#8220;弹出&#8221;操作快速地将后台缓冲区与主平面互换（指针的互换），从而获得高速的视频动画效果。只有具有可&#8220;弹出&#8221;属性的平面才能使用&#8220;弹出&#8221;操作。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>释放。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>在DirectX中，各个对象均有Release方法，这个方法（成员函数）并不见得就是销毁对象，它只是对内部计数器进行递减操作。例如，用DirectDrawCreate()函数建立了DirectDraw基本对象后，该对象的内部计数器就置为值1，如果此时再调用该对象的Release方法，就会使内部计数器减去1，若结果为零则该对象被销毁，但若在调用Release方法之前又为该对象请求新的接口（如IDirectDraw2），则内部计数器又会加一，需要两次Release方法才能完全销毁该对象。&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　在示例程序一中，从WinMain函数开始，在登记了窗口类并建立了程序主窗口后，就开始建立DirectDraw的基本对象了：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>ddrval&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;DirectDrawCreate(NULL,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">_lpDD,&nbsp;NULL);<br><img id=Codehighlighter1_4461_4565_Open_Image onclick="this.style.display='none'; Codehighlighter1_4461_4565_Open_Text.style.display='none'; Codehighlighter1_4461_4565_Closed_Image.style.display='inline'; Codehighlighter1_4461_4565_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_4461_4565_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_4461_4565_Closed_Text.style.display='none'; Codehighlighter1_4461_4565_Open_Image.style.display='inline'; Codehighlighter1_4461_4565_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(ddrval</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">DD_OK)</span><span id=Codehighlighter1_4461_4565_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_4461_4565_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;失败</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　函数DirectDrawCreate在成功时返回DD_OK（零），若是失败则返回一个32位（HRESULT）的错误代码。不止是这个函数，所有DirectX对象的成员函数（方法）均采用这种方式来返回表示成功或失败的值。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　不必去管该函数的第一个和第三个参数，现在只需要把它们设为空值即可，而第二个参数是一个指针，这个指针指向了一个LPDIRECTDRAW类型的变量，而该变量实际上也是一个指针，如果函数成功则指向IDirectDraw对象实体</span><span style="COLOR: #000000">--------</span><span style="COLOR: #000000">是不是有一点绕来绕去的？<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　当基本对象成功建立后，就需要将它&#8220;变&#8221;成较新的对象以增进性能，这也正是本示例程序为什么需要5.0版本的DirectX来支持的缘故。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>ddrval</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">_lpDD</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">QueryInterface(IID_IDirectDraw2,&nbsp;(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">**</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">lpDD);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_lpDD</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Release();<br><img id=Codehighlighter1_5079_5183_Open_Image onclick="this.style.display='none'; Codehighlighter1_5079_5183_Open_Text.style.display='none'; Codehighlighter1_5079_5183_Closed_Image.style.display='inline'; Codehighlighter1_5079_5183_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_5079_5183_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_5079_5183_Closed_Text.style.display='none'; Codehighlighter1_5079_5183_Open_Image.style.display='inline'; Codehighlighter1_5079_5183_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(ddrval</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">DD_OK)</span><span id=Codehighlighter1_5079_5183_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_5079_5183_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;失败</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　下一步是利用新建立的基本对象来建立与该基本对象相关联的主平面，这个主平面实际上就是可视的屏幕，所有对主平面的访问都直接反映在屏幕。在建立主平面之前我们首先将基本对象的属性设为全屏幕独占方式，这样才能改变显示模式，以及建立可&#8220;弹出&#8221;的平面集。具体的设置方法参见源程序。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　在设置了全屏幕独占方式并设置了适当的显示模式之后，程序建立了一个主平面，这个主平面附带一个后台缓冲区，程序员可以使用&#8220;设备相关把柄（HDC）&#8221;或直接访问的方式（以后再讲）来对后台缓冲区进行图形操作，所有对后台缓冲区的操作并不能反映在屏幕上，在图形操作完成后，可以利用&#8220;弹出&#8221;操作来将后台缓冲区&#8220;弹&#8221;至主平面，从而在屏幕上显示出来。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　本示例程序在进行图形操作示例时，首先获取后台缓冲区的HDC，然后用标准的GDI函数来绘制文本，一旦绘制完毕，就立刻释放刚获取的HDC，因为任何一个平面的HDC被获取后，该平面就被隐式地锁定，无法进行位块拷贝或弹出操作，只有当该HDC被释放后，一个隐式的Unlock才被调用，程序才能对该平面进行前述操作。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　完成后台缓冲区的图形绘制后，程序调用主平面的成员函数（方法）Flip来将后台缓冲区弹至主平面，你将看到屏幕内容已被改变。<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>　　这是我个人搞的一个小封装，可用于非C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">的编程语言（如Delphi）。使用此封装库可比较容易地编制DirectDraw应用程序。此封装为静态链接库，提供Visual&nbsp;C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">和BorlandC</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">两种版本，其中包括：<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Visual&nbsp;C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">版库文件<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Borland&nbsp;C</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">版库文件<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;相关的头文件<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;两个示例源程序<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;说明文档（HLP文档格式）<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<img src ="http://www.cppblog.com/iniwf/aggbug/86476.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-06-01 22:58 <a href="http://www.cppblog.com/iniwf/archive/2009/06/01/86476.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DircetDraw c/c++ 使用指导(四)</title><link>http://www.cppblog.com/iniwf/archive/2009/05/25/85700.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 25 May 2009 06:38:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/05/25/85700.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/85700.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/05/25/85700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/85700.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/85700.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DirectDraw_4.htm">http://dev.gameres.com/Program/Visual/2D/DirectDraw_4.htm</a><br><br>
<table height=211 cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="21%" height=49><a href="http://www.gameres.com/"><img height=47 alt=中国游戏技术资源网 src="http://dev.gameres.com/images/titlesmall.jpg" width=200 border=0></a></td>
            <td width="45%" height=49></td>
            <td width="34%" height=49></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3 height=18><font face=Tahoma size=2>&nbsp;</font></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3 height=21>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#1d2532>
                        <p align=right><font face=Tahoma size=2>译：310cdt　</font> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3 height=41>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%"><font face=Tahoma size=2>&nbsp;</font></td>
                    </tr>
                    <tr>
                        <td width="100%">
                        <p align=center><font face=Tahoma color=#ffffdd><strong>DircetDraw c/c++ 使用指导(四)</strong></font> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3 height=61>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <div align=center>
                        <table cellSpacing=0 cellPadding=0 width="95%" border=0>
                            <tbody>
                                <tr>
                                    <td width="100%"><font face=Tahoma size=2><br>ddex4(不过这两天不知怎的服务器不怎么好使,过两天可能会好)</font>
                                    <p><font face=Tahoma size=2><strong>tutorial4:</strong>色彩键码和位图动画<br>第三篇指导的例子ddex3演示了一个简单的在翻转页面前把位图放到离屏缓存的行为.这篇指导的例子将利用前面描述的技术,装载一个背景图片和一系列的精灵(译者注:一般放置小幅的不断改变的图片)到离屏表面中.然后,使用IDirectDrawSurface7::BltFast方法拷贝离屏表面的一部分到后台缓冲,以次,产生一个简单的位图动画.<br>ddex4用到的位图文件是all.bmp,它包含了背景和60个连续的黑背景的旋转的红圈.DDEx4包含了新的函数,用来为旋转红圈精灵设置色彩键码.然后,例子从离屏表面中拷贝适当的精灵到后台缓冲.<br>DDEx4中新添的函数演示如下:<br><strong>step1:</strong>设置色彩键码<br><strong>step2:</strong>建立一个简单的动画<br>(译者注:色彩键码就是设置了的,在从离屏表面向缓冲拷贝的时候不拷贝的色彩,从而形成透明的样子)</font></p>
                                    <p><font face=Tahoma size=2><strong>step1:</strong>设置色彩键码<br>在其他例子的基础上,ddex4的doInit函数包含了设置精灵色彩键码的代码.色彩键码是用来设置一个色彩值,这个色彩值是用于透明的.当系统使用硬件块移动支持时,所有的像素中除了设为色彩键码的颜色的,都将被块移动(blit)到缓存.这样就创建了一个不是矩形样子的精灵.下面的代码演示了DDEx4中如何设置色彩键码的.</font></p>
                                    <p><font face=宋体 color=#99ccff size=2>// Set the color key for this bitmap (black).<br>DDSetColorKey(lpDDSOne, RGB(0,0,0));<br>&nbsp;<br>return TRUE;</font><font face=Tahoma size=2><br><br>在DDSetColorKey函数的调用的时候,你可以设置你想设的颜色的RGB值来设置色彩键码.黑色的RGB值是(0,0,0).DDSetColorKey函数调用了DDColorMatch函数.(两个函数都在ddutil.cpp中) DDColorMatch函数储存了在lpDDSOne表面中的位图的(0,0)位置的像素的颜色值.然后,他把位图的(0,0)位置的像素设为你提供的那个颜色.最后,它求了颜色值和每个像素色彩位数的掩码(异或).使(0,0)位置变回了原来的颜色,当这些都做完后,函数调用完返回到DDSetColorKey中.返回了色彩键码的值(dw)值.放在了DDCOLORKEY结构的成员dwColorSpaceLowValue中,并被拷贝到dwColorSpaceHighValue成员中.随后IDirectDrawSurface7::SetColorKey的调用设置了色彩键码.<br>你可能已经注意到了DDSetColorKey和DDColorMatch函数中的CLR_INVALID了.如果在DDEx4中你把CLR_INVALID当作色彩键码传递给DDSetColorKey函数,位图中的左上角(0,0)像素将被当作色彩键码.DDEx4中这个意义不大,因为位图的(0,0)位置是灰色的.你要是想看看怎样在ddex4中让(0,0)位置作为色彩键码,你可以用绘图软件打开all.bmp文件.然后把(0,0)这个点改为黑色.一定要保证你把修改保存好了(这个不好看出来).然后,你可以把DDSetColorKey的调用改成下面这样:<br><br></font><font face=宋体 color=#99ccff size=2>DDSetColorKey(lpDDSOne, CLR_INVALID);</font></p>
                                    <p><font face=Tahoma size=2>重新编译ddex4,保证包含了新位图的资源文件也重新编译过了.这样,ddex4将用那个现在已经被改为黑色的(0,0)点作为色彩键码了.</font></p>
                                    <p><font face=Tahoma size=2><br><strong>step2:</strong>创建一个简单的动画<br>ddex4用到了updateFrame例子函数创建了一个简单的动画,用的是all.bmp中包含的那些红圈.这个动画由三个呈三角形位置的以不同速度转动的红圈组成.例子中通过比较win32 GetTickCount函数和上一次调用GetTickCount函数到现在的毫秒数来决定是否重绘精灵.然后,使用IDirectDrawSurface7::BltFast方法把背景从离屏表面(lpDDSOne)中块移动(blit)到后台缓存,并且把精灵们也块移动到后台缓存,这是要用到你刚才设置的色彩键码决定哪些像素是透明的.当精灵们移动到后台缓存后,就调用IDirectDrawSurface7::Flip方法翻转页面.<br>注意当你用IDirectDrawSurface7::BltFast方法块移动背景的时候,dwTrans参数定义了传送的参数是DDBLTFAST_NOCOLORKEY.这个标示了将是一个没有透明的普通块移动.后来,当红圈被块移动的时候,dwTrans参数设为DDBLTFAST_SRCCOLORKEY.这个标示了块移动将用到定义了的色彩键码,以实现透明的效果.在这个例子中,是对lpDDSOne缓存.<br>在这个例子中,每次调用updateFrame函数都将重绘全部背景.优化这个例子的一个方法是,只重绘红圈旋转所引起的背景发生变化的那一小部分.因为放置红圈精灵的位置和大小都是不变得,所以,你可以很简单的修改ddex4以达到这个优化.</font><font face=Tahoma color=#c0c0c0 size=2><br>　</font></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </div>
                        </td>
                    </tr>
                    </center>
                    <tr>
                        <td width="100%" bgColor=#1d2532><font face=Tahoma size=2>　</font></td>
                    </tr>
                    <tr>
                        <td width="100%"><font face=Tahoma size=2>&nbsp;</font></td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3 height=21></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/85700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-05-25 14:38 <a href="http://www.cppblog.com/iniwf/archive/2009/05/25/85700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DircetDraw c/c++ 使用指导(三)</title><link>http://www.cppblog.com/iniwf/archive/2009/05/25/85699.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 25 May 2009 06:33:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/05/25/85699.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/85699.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/05/25/85699.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/85699.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/85699.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DirectDraw_3.htm">http://dev.gameres.com/Program/Visual/2D/DirectDraw_3.htm</a><br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="21%"><a href="http://www.gameres.com/"><img height=47 alt=中国游戏技术资源网 src="http://dev.gameres.com/images/titlesmall.jpg" width=200 border=0></a></td>
            <td width="45%"></td>
            <td width="34%"></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3><font face=Tahoma>&nbsp;</font></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#1d2532>
                        <p align=right><font face=Tahoma size=2>译：310cdt</font><font face=Tahoma>　</font> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%"><font face=Tahoma>&nbsp;</font></td>
                    </tr>
                    <tr>
                        <td width="100%">
                        <p align=center><strong><font face=Tahoma color=#ffffdf>DircetDraw c/c++ 使用指导(三)</font></strong> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <div align=center>
                        <table cellSpacing=0 cellPadding=0 width="95%" border=0>
                            <tbody>
                                <tr>
                                    <td width="100%"><font face=Tahoma size=2><br>这几篇指导的例程我放到网上了</font>
                                    <p><font face=Tahoma size=2><a style="COLOR: #ff9933" href="http://brizy310cdt.home.chinaren.com/ddex1.zip"><u>ddex1</u></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font face=Tahoma color=#c0c0c0 size=2><a style="COLOR: #ff9933" href="http://brizy310cdt.home.chinaren.com/ddex2.zip"><u>ddex2</u></a></font><font face=Tahoma size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font face=Tahoma color=#c0c0c0 size=2><a style="COLOR: #ff9933" href="http://brizy310cdt.home.chinaren.com/ddex3.zip"><u>ddex3</u></a><br></font><font face=Tahoma size=2>tutorial3:从一个离屏表面(off-screen surface)的块移动(blt)</font></p>
                                    <p><font face=Tahoma size=2>在ddex2中,把一张位图放到了后台缓存中,然后在缓存与主平面间翻啊翻...其实这不是显示位图的一般行为.在这一篇中(例子是ddex3)将要通过包含两个离屏表面来扩展ddex2的能力.两个位图-一个是第偶数次显示的,一个是奇数次显示-存放在这两个离屏表面.例子中,用IDirectDrawSurface7::BltFast方法把离屏表面的内容拷贝到后台缓存中去,然后翻转,然后再把下一个离屏表面拷到缓存...<br>(译者注:这一篇只是演示离屏表面和blit的方法,实际上,离屏表面使用的时候大部分是用来存放精灵,实现动画的.存放的都是小的图片,是一个特殊的平面)<br>ddex3新的函数以下面3个步骤演示:<br>step1:建立离屏表面<br>step2:载入位图到离屏表面<br>step3:块移动(blit)离屏表面到后台缓冲</font></p>
                                    <p><font face=Tahoma size=2><br>step1:建立离屏表面<br>下面的代码是加入到doInit函数中创建两个离屏表面.<br><br></font><font face=宋体 color=#99ccff size=2>// Create an off-screen bitmap.<br>ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;<br>ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;<br>ddsd.dwHeight = 480;<br>ddsd.dwWidth = 640;<br>ddrval = lpDD-&gt;CreateSurface(&amp;ddsd, &amp;lpDDSOne, NULL);<br>if(ddrval != DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; return initFail(hwnd);<br>}<br>&nbsp;<br>// Create another off-screen bitmap.<br>ddrval = lpDD-&gt;CreateSurface(&amp;ddsd, &amp;lpDDSTwo, NULL);<br>if(ddrval != DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; return initFail(hwnd);<br>}</font><font face=Tahoma size=2><br><br>dwFlags成员定义了程序将使用DDSCAPS结构,并且将要设置离屏表面的高和宽.这个表面因为标示了DDSCAPS_OFFSCREEN在DDSCAPS结构中,所以将会是一个完全的离屏的缓存.高和宽分别设为480 和640.随后,表面经过IDirectDraw7::CreateSurface方法创建.<br>因为两个离屏表面大小相同,就又不同的指针调用了IDirectDraw7::CreateSurface又一次,创建了另一个.<br>你可以通过在DDSCAPS结构中定义DDSCAPS_SYSTEMMEMORY或DDSCAPS_VIDEOMEMORY来决定将离屏表面放在系统内存还是显存中.放在显存中,你可以加快离屏表面到后台缓存的移动速度.将用到位图的动画的时候,这将十分的重要.但是,如果你使用DDSCAPS_VIDEOMEMORY并且没有足够的显存区存放那个位图了,当你试图创建这个表面的时候,将会返回一个DDERR_OUTOFVIDEOMEMORY错误.</font></p>
                                    <p><font face=Tahoma size=2>&nbsp;</font></p>
                                    <p><font face=Tahoma size=2>step2:载入位图到离屏表面<br>当两个离屏表面创建好后,DDEx3用InitSurface函数将frntback.bmp文件的位图装入到表面中.InitSurface函数用到了ddutil.cpp文件中的DDCopyBitmap函数去装载位图.如下:<br><br></font><font face=宋体 color=#99ccff size=2>// Load the bitmap resource.<br>hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap,<br>&nbsp;&nbsp;&nbsp; IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);<br>&nbsp;<br>if (hbm == NULL)<br>&nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;<br>DDCopyBitmap(lpDDSOne, hbm, 0, 0,&nbsp;&nbsp; 640, 480);<br>DDCopyBitmap(lpDDSTwo, hbm, 0, 480, 640, 480);<br>DeleteObject(hbm);<br>&nbsp;<br>return TRUE;</font><font face=Tahoma size=2><br><br>如果你用看图或画图的软件看过frntback.bmp文件了,你就知道,这个文件包括两个图,一个在另一个的上面.DDCopyBitmap函数把这个位图从分界的地方分成两部分.一个装入到第一个离屏表面(lpDDSOne),另一个在第二个离屏表面(lpDDSTwo).</font></p>
                                    <p><font face=Tahoma size=2><br>step3:块移动(blit)离屏表面到后台缓冲<br>WM_TIMER消息触发的代码包括写入表面和翻转表面.在DDEx3中,他包含了下面的代码去选择适当的离屏表面,然后把他块移动(blit)到后台缓存.<br><br></font><font face=宋体 color=#99ccff size=2>rcRect.left = 0;<br>rcRect.top = 0;<br>rcRect.right = 640;<br>rcRect.bottom = 480;<br>if(phase)<br>{<br>&nbsp;&nbsp;&nbsp; pdds = lpDDSTwo;<br>&nbsp;&nbsp;&nbsp; phase = 0;<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; pdds = lpDDSOne;<br>&nbsp;&nbsp;&nbsp; phase = 1;<br>}<br>while(1)<br>{<br>&nbsp;&nbsp;&nbsp; ddrval = lpDDSBack-&gt;BltFast(0, 0, pdds, &amp;rcRect, FALSE);<br>&nbsp;&nbsp;&nbsp; if(ddrval == DD_OK)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; }<br>}</font><font face=Tahoma size=2><br><br>phase变量决定了到底是哪一个离屏表面将被移动到后台缓存.IDirectDrawSurface7::BltFast方法的调用是用来把所选的离屏表面块移动到后台缓存的.在(0,0)处开始,左上角.reRect参数指向一个RECT结构,他定义了移动出来的离屏表面的左上和右下角.最后的一个参数设为FALSE(0),标示没有使用特殊的传输标示符.<br>根据你的程序的需要,你可以使用IDirectDrawSurface7::Blt 或者IDirectDrawSurface7::BltFast 方法实现块移动.如果你的离屏表面在显存中,你最好使用IDirectDrawSurface7::BltFast 方法.这样做,如果你使用的是硬件块移动支持的系统,你不会获得更快的速度,但是,如果使用的硬件模仿的块移动,你将会少用10%的时间.所以,你应该使用IDirectDrawSurface7::BltFast方法去做所有的在显存中的块移动.如果你从系统内存中移动,或者需要特别的硬件标志,那就只好使用IDirectDrawSurface7::Blt了.<br>当完成的从离屏表面到后台缓存的块移动,后台缓存就和主平面之间像前面几篇一样不停的翻啊翻....</font><font face=Tahoma color=#c0c0c0 size=2><br>　</font></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </div>
                        </td>
                    </tr>
                    </center>
                    <tr>
                        <td width="100%" bgColor=#1d2532><font face=Tahoma>　</font></td>
                    </tr>
                    <tr>
                        <td width="100%"><font face=Tahoma>&nbsp;</font></td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/85699.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-05-25 14:33 <a href="http://www.cppblog.com/iniwf/archive/2009/05/25/85699.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DircetDraw c/c++ 使用指导(二)</title><link>http://www.cppblog.com/iniwf/archive/2009/05/25/85698.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 25 May 2009 06:32:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/05/25/85698.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/85698.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/05/25/85698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/85698.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/85698.html</trackback:ping><description><![CDATA[<a href="http://dev.gameres.com/Program/Visual/2D/DirectDraw_2.htm">http://dev.gameres.com/Program/Visual/2D/DirectDraw_2.htm</a><br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="21%"><a href="http://www.gameres.com/"><img height=47 alt=中国游戏技术资源网 src="http://dev.gameres.com/images/titlesmall.jpg" width=200 border=0></a></td>
            <td width="45%"></td>
            <td width="34%"></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3><font face=Tahoma>&nbsp;</font></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#1d2532>
                        <p align=right><font face=Tahoma size=2>译：310cdt</font><font face=Tahoma>　</font> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%"><font face=Tahoma>&nbsp;</font></td>
                    </tr>
                    <tr>
                        <td width="100%">
                        <p align=center><strong><font face=Tahoma color=#ffffee>DircetDraw c/c++ 使用指导(二)</font></strong> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <div align=center>
                        <table cellSpacing=0 cellPadding=0 width="95%" border=0>
                            <tbody>
                                <tr>
                                    <td width="100%"><font face=Tahoma size=2><br><strong>Tutorial2:在缓存中载入位图</strong></font><strong> </strong>
                                    <p><font face=Tahoma size=2>这个例子讨论在ddex1的基础上进行扩展.ddex2(例程在msdn上就有,搜索...)讲包含载入位图文件的函数.新的功能靠以下的步骤实现:<br>step1:创建调色板<br>step2:设置调色板<br>step3:在缓存中载入位图<br>step4:翻转平面.<br>像在ddex1中一样,在初始化函数中初始化了ddex2.<br>不同的代码如下:<br><br></font><font face=宋体 color=#99ccff size=2>lpDDPal = DDLoadPalette(lpDD, szBackground);<br>&nbsp;<br>if (lpDDPal == NULL)<br>&nbsp;&nbsp;&nbsp; goto error;<br>&nbsp;<br>ddrval = lpDDSPrimary-&gt;SetPalette(lpDDPal);<br>&nbsp;<br>if(ddrval != DD_OK)<br>&nbsp;&nbsp;&nbsp; goto error;<br>&nbsp;<br>// Load a bitmap into the back buffer.<br>ddrval = DDReLoadBitmap(lpDDSBack, szBackground);<br>&nbsp;<br>if(ddrval != DD_OK)<br>&nbsp;&nbsp;&nbsp; goto error;</font></p>
                                    <p><font face=Tahoma size=2>Step1:建立调色板<br>在ddex2中,首先用如下代码建立调色板.<br><br></font><font face=宋体 color=#99ccff size=2>lpDDPal = DDLoadPalette(lpDD, szBackground);<br>&nbsp;<br>if (lpDDPal == NULL)<br>&nbsp;&nbsp;&nbsp; goto error;</font><font face=Tahoma size=2><br><br>DDLoadPalette这个函数是在\Dxsdk\sdk\samples\misc\ddutil.cpp中的公共directdraw函数.很多directdraw的例子(sdk包中的)都用到这个文件.重要的是,它包含了载入调色板和位图的函数,无论是从文件还是资源.为了不重复的写代码,就把他放在了一个可以重复使用的文件中.确信你在编译ddexn是包含了这文件.<br>(以下内容在ddutial.cpp中)ddex2中,DDLoadPalette函数从back.bmp文件创建了DirectDrawPalette对象.DDLoadPalette函数判断创建调色板的文件或资源是否存在.如果不是的话,就创建一个默认的调色板.在ddex2中,他从位图文件提取调色板信息并储存在一个ape指向的结构中.<br>DDEx2随后创建了DirectDrawPalette对象,如下:<br><br></font><font face=宋体 color=#99ccff size=2>pdd-&gt;CreatePalette(DDPCAPS_8BIT, ape, &amp;ddpal, NULL);<br>return ddpal;</font><font face=Tahoma size=2><br><br>当IDirectDraw7::CreatePalette方法返回,ddpal参数指向从DDLoadPalette函数返回的DirectDrawPalette对象.<br>ape参数是一个指针,指向一个能包含或者2或4或16或256个线性组织的纪录的结构.记录的数目依靠于CreatePalette方法中的dwFlags参数.在上面的情况下,dwFlags参数设为DDPCAPS_8BIT.这表示结构中有256个记录.每一条记录包含4字节(分别是红,绿,兰的通道和一个标志位).</font></p>
                                    <p><font face=Tahoma size=2>Step2:设置调色板<br>创建完调色板以后,通过指针调用主平面的IDirectDrawSurface7::SetPalette方法,如下:<br><br></font><font face=宋体 color=#99ccff size=2>ddrval = lpDDSPrimary-&gt;SetPalette(lpDDPal);<br>&nbsp;<br>if(ddrval != DD_OK)<br>&nbsp;&nbsp;&nbsp; goto error;// SetPalette failed.</font><font face=Tahoma size=2><br><br>在你调用完IDirectDrawSurface7::SetPalette方法之后,DirectDrawPalette对象就与DirectDrawSurface对象联系起来了.什么时候你想改变调色板了,可以简单的创建一个新的调色板,然后设置一下就可以了.(虽然这篇指导用了这些步骤,其实还有其他的方法改变调色板,以后的例子中将会演示)<br><br>Step3:在缓存区载入位图<br>DirectDrawPalette对象与DirectDrawSurface对象联系起来之后,DDEx2用下面的代码在缓存中载入位图back.bmp<br><br></font><font face=宋体 color=#99ccff><font size=2>// Load a bitmap into the back buffer.<br>ddrval = DDReLoadBitmap(lpDDSBack, szBackground);<br>&nbsp;<br>if(ddrval != DD_OK)<br>&nbsp;&nbsp;&nbsp; // Load failed.<br></font></font><font face=Tahoma size=2><br>DDReLoadBitmap是另一个在Ddutil.cpp中的函数.他载入一个位图文件或资源到一个已经存在的DirectDraw平面.(你也可以使用DDLoadBitmap函数创建一个平面然后载入.函数也在ddutil.cpp中.)在ddex2中,他载入由szBackground(ID)指向的back.bmp文件到由lpDDSBack(指针)指向的后台缓存.DDReLoadBitmap函数调用DDCopyBitmap函数将文件拷贝到缓存,并拉伸到适当的大小.<br>DDCopyBitmap函数将位图拷贝到内存中,用GetObject函数恢复位图的大小.然后是由下面的代码将位图调整到将要放位图的缓存的大小.<br><br></font><font face=宋体 color=#99ccff><font size=2>// Get the size of the surface.<br>ddsd.dwSize = sizeof(ddsd);<br>ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;<br>pdds-&gt;GetSurfaceDesc(&amp;ddsd);<br></font></font><font face=Tahoma size=2><br>ddsd是一个DDSURFACEDESC2结构的指针.这个结构保存了现在的DirectDraw平面的描述.在这种情况下,DDSURFACEDESC2的成员描述了平面的高和宽,由DDSD_HEIIGHT和DDSD_WIDTH标示的.IDirectDrawSurface7::GetSurfaceDesc方法的调用把属性值装入了这个结构.在DDEX2中,值将被设为高480,宽640.<br>DDCopyBitmap函数给平面加锁然后把位图拷贝到缓存中,用StretchBlt函数拉伸或压缩.如下:<br><br></font><font face=宋体 color=#99ccff><font size=2>if ((hr = pdds-&gt;GetDC(&amp;hdc)) == DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dx, dy, SRCCOPY);<br>&nbsp;&nbsp;&nbsp; pdds-&gt;ReleaseDC(hdc);<br>}</font></font></p>
                                    <p><font face=Tahoma size=2>Step4:翻转页面<br>ddex2中翻转页面的部分与ddex1中的十分的相像.所不同的是:当平面丢失时(DDERR_SURFACELOST),在平面储存后,必须用DDReLoadBitmap函数将位图重新载入缓存.<br>　</font></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </div>
                        </td>
                    </tr>
                    </center>
                    <tr>
                        <td width="100%" bgColor=#1d2532><font face=Tahoma>　</font></td>
                    </tr>
                    <tr>
                        <td width="100%"><font face=Tahoma>&nbsp;</font></td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/iniwf/aggbug/85698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-05-25 14:32 <a href="http://www.cppblog.com/iniwf/archive/2009/05/25/85698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DircetDraw c/c++ 使用指导(一) </title><link>http://www.cppblog.com/iniwf/archive/2009/05/25/85697.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 25 May 2009 06:29:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/05/25/85697.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/85697.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/05/25/85697.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/85697.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/85697.html</trackback:ping><description><![CDATA[<p><a href="http://dev.gameres.com/Program/Visual/2D/DirectDraw_1.htm">http://dev.gameres.com/Program/Visual/2D/DirectDraw_1.htm</a><br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width="21%"><a href="http://www.gameres.com/"><img height=47 alt=中国游戏技术资源网 src="http://dev.gameres.com/images/titlesmall.jpg" width=200 border=0></a></td>
            <td width="45%"></td>
            <td width="34%"></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3><font face=Tahoma size=2>&nbsp;</font></td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#1d2532>
                        <p align=right><font face=Tahoma size=2>译：310cdt　</font> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%"><font face=Tahoma size=2>&nbsp;</font></td>
                    </tr>
                    <tr>
                        <td width="100%">
                        <p align=center><strong><font face=Tahoma color=#ffffdf>DircetDraw c/c++ 使用指导(一)</font></strong> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3>
            <div align=center>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td width="100%">
                        <div align=center>
                        <table cellSpacing=0 cellPadding=0 width="95%" border=0>
                            <tbody>
                                <tr>
                                    <td width="100%"><font face=Tahoma size=2><br>边看边译,译完就拿了上来,见笑了</font>
                                    <p><font face=Tahoma size=2>这是一系列的DirectDraw的指南,教你一步步的去构建一个简单的DirectDraw应用.这个指南用到了sdk包提供的很多DirectDraw的例子.这些例子展示了怎样设置DirectDraw,怎样用DirectDraw方法实现一般任务:</font></p>
                                    <p><font face=Tahoma size=2><br>注意:这些指南中的例子是用c++写的.如果你使用的是c编译器,请进行适当的改变,以能进行成功的编译.你需要把vtable和this指针添加到接口方法中.</font></p>
                                    <p><font face=Tahoma size=2>&nbsp;</font></p>
                                    <p><strong><font face=Tahoma size=2>1.DirectDraw基础用法</font></strong></p>
                                    <p><font face=Tahoma size=2>要使用DirectDraw,你必须先创建一个代表计算机显示接口的DirectDraw实例.然后,你就可以通过接口的方法来操纵这个对象.你可能会需要创建一个或更多的DirectDraw平面对象(DirectDraw surface object)的实例<br>来在图形设备上显示你的应用程序.</font></p>
                                    <p><font face=Tahoma size=2>为了演示这个,例子DDEx1 sample((SDK root)\Samples\Multimedia\DDraw\Src\Ddex1)演示了以下几步:</font></p>
                                    <p><font face=Tahoma size=2>step 1:创建一个DirectDraw对象<br>想创建一个DirectDraw对象的实例,你的应用程序必须在InitApp函数中使用DirectDrawCreateEx函数,就像例程ddex1中一样.DirectDrawCreateEx函数包括4个参数.第一个是:显示设备全局唯一标识(GUID).GUID大部分情况下是设为NULL,选择系统默认的显示设备.第二个参数是:包含的是标示DirectDraw对象是否建立的指针的地址.第三个参数是IDirectDraw7接口的参考标示.必须设为IID_IDirectDraw7.第四个参数是设置为NULL的,是为了将来的扩展做准备的.<br>以下的例子展示了怎样创建DirectDraw对象,并判断创建是否成功.<br><br></font><font face=宋体 color=#99ccff size=2>hRet = DirectDrawCreateEx(NULL, (VOID**)&amp;g_pDD, IID_IDirectDraw7, NULL);<br>if(hRet == DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; // g_pDD is a valid DirectDraw object.<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; // The DirectDraw object could not be created.<br>}</font></p>
                                    <p><font face=Tahoma size=2>&nbsp;</font></p>
                                    <p><font face=Tahoma size=2>step2:决定程序的行为<br>在你改变显示方法前,你必须至少在IDirectDraw7::SetCooperativeLevel函数中指定dwFlags参数(DDSCL_EXCLUSIVE 和 DDSCL_FULLSCREEN).这样,你的应用程序就得到了显示设备的全部控制权,其他的程序不能共享.DDSCL_FULLSCREEN让你的应用程序在全屏幕模式下运行.你的程序覆盖了桌面,并且只有你的程序能在屏幕上输出.但是,桌面仍然是有效的.(按ALT+TAB切换到桌面)</font></p>
                                    <p><font face=Tahoma size=2>下面的例子演示了SetCooperativeLevel函数的用法.<br><br></font><font face=宋体 color=#99ccff size=2>HRESULT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hRet;<br>LPDIRECTDRAW7 g_pDD;&nbsp;&nbsp; // already created by DirectDrawCreateEx</font></p>
                                    <p><font face=宋体 color=#99ccff size=2>hRet = g_pDD-&gt;SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);<br>if (hRet != DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; // Exclusive mode was successful.<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; // Exclusive mode was not successful.<br>&nbsp;&nbsp;&nbsp; // The application can still run, however.<br>}</font></p>
                                    <p><font face=Tahoma size=2>如果 SetCooperativeLevel不返回DD_OK,你可以指定为DDSCL_NORMAL继续运行你的程序.但是,你的程序不再是独占模式,而且,可能会无法完成你的一部分要求.在这种情况下,你最好显示一个对话框让用户决定是否要继续.<br>如果你设置的是全屏幕独占合作级别,你必须把程序的窗口句柄传递给SetCooperativeLevel,这样可以让Windows有能力决定你的程序是否异常终止.</font></p>
                                    <p><font face=Tahoma size=2>&nbsp;</font></p>
                                    <p><font face=Tahoma size=2>step3 :改变显示模式<br>接下来,你可以用IDirectDraw7::SetDisplayMode函数来改变显示模式.下面的例子将演示怎样把显示模式设置为640 &#215; 480 &#215; 8 bits per pixel (bpp).<br><br></font><font face=宋体 color=#99ccff size=2>HRESULT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hRet;<br>LPDIRECTDRAW7 g_pDD;&nbsp;&nbsp; // already created by DirectDrawCreateEx</font></p>
                                    <p><font face=宋体 color=#99ccff size=2>hRet = g_pDD-&gt;SetDisplayMode(640, 480, 8, 0, 0);<br>if (hRet != DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; // The display mode changed successfully.<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; // The display mode cannot be changed.<br>&nbsp;&nbsp;&nbsp; // The mode is either not supported or<br>&nbsp;&nbsp;&nbsp; // another application has exclusive mode.<br>}</font></p>
                                    <p><font face=Tahoma size=2>当你设置显示模式的时候,你应该确定用户的硬件是否支持这样的模式.你可以设置一个能被大部分显示适配器支持的标准的模式.例如:你的程序可以以640 &#215; 480 &#215; 8作为备选模式,设计成为可以在所有系统上运行.<br>注意:IDirectDraw7::SetDisplayMode返回一个DDERR INVALIDMODE错误值,如果显示适配器无法切换到想要的模式时.你可以在试图改变显示模式前,用IDirectDraw7::EnumDisplayModes函数看一下用户显示适配器的能力.</font></p>
                                    <p><font face=Tahoma size=2><br>step4:创建交换页(flipping surface)<br>设置完显示模式以后,你应该创建一个平面.例程:DDEx1用IDirectDraw7::SetCooperativeLevel 设置为独占模式.所以,你可以创建交换页(flipping surfaces).如果你设置的是DDSCL_NORMAL模式,你可以创建一个可以块移动(blit)的平面.创建交换页(flipping surfaces)需要以下步骤:<br>(4.1)定义需求的平面:<br>第一步是以DDSURFACEDESC2结构定义一个需求的平面.下面的例子演示了结构的定义和标志位的设定:<br><br></font><font face=宋体 color=#99ccff size=2>// Create the primary surface with one back buffer.<br>ZeroMemory(&amp;ddsd, sizeof(ddsd));<br>ddsd.dwSize = sizeof(ddsd);<br>ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;<br>ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DDSCAPS_COMPLEX;<br>ddsd.dwBackBufferCount = 1;</font></p>
                                    <p><font face=Tahoma size=2>在这个例子中,dwSize成员是DDSURFACEDESC2结构的大小.这是防止你用到的DirectDraw方法返回无效成员的错误.(dwSize是准备给将来的DDSURFACEDESC2结构的扩展用的)<br>dwFlags成员决定的DDSURFACEDESC2结构中那些成员将被填充有效的信息.例如在DDEx1中,dwFlags被设为你想要用DDSCAPS结构(DDSD_CAPS)和你想创建一个后台缓冲(back buffer)(DDSD_BACKBUFFERCOUNT)<br>dwCaps成员在例子中标示一个将要在DDSCAPS结构中使用的标志位.在这种情况下,他指定一个主平面(primary surface DDSCAPS_PRIMARYSURFACE),一个交换页(flipping surface DDSCAPS_FLIP),一个合成表面(complex surface DDSCAPS_COMPLEX).<br>最后,例子指定了一个后台缓冲.后台缓冲就是实际的绘图操作先在那里完成,然后,再快速的翻动(flip)到主平面(primary surface)上.在DDEx1中,后台缓冲的数目是1.其实,你要你的显存允许,你想建几个就建几个.你想知道更多的关于创建大于1块缓冲的信息,可以去看&nbsp; "triple buffering".<br>创建的"平面"占用的存储空间,可以是系统内存也可以是显存.如果应用程序使用的空间超出了显存,DirectDraw就会使用系统内存.(例如你指定多块缓存在一个仅有1MB显存的是配器上).你也可以这样设置DDSCAPS结构的dwCaps成员,设成DDSCAPS_VIDEOMEMEORY或DDCAPS_SYSTEMMEMORY以达到只用显存或只用内存.(如指定用显存,而显存不够,IDirectDraw7::CreateSurface返回一个DDERR_OUTOFVIDEOMEMORY错误)<br>(4.2)创建平面<br>在填充完DDSURFACEDESC2结构后,你就可以用他和g_pDD指针(DirectDrawCreateEx函数创建的DirectDraw对象的指针)调用IDirectDraw7::CreateSurface方法,就像下面 :<br><br></font><font face=宋体 color=#99ccff size=2>hRet = g_pDD-&gt;CreateSurface(&amp;ddsd, &amp;g_pDDSPrimary, NULL);<br>if (hRet != DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; // g_pDDSPrimary points to the new surface.<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; // The surface was not created.<br>&nbsp;&nbsp;&nbsp; return FALSE;<br>}</font><font face=Tahoma size=2><br><br>g_pDDSPrimary参数将指向由CreateSurface函数返回的主平面(primary surface)的地址,如果调用成功的话.<br>指向主平面(primary surface)的指针有效后,就可以调用IDirectDrawSurface7::GetAttachedSurface方法去得到一个指向缓冲的指针.如下:<br><br></font><font face=宋体 color=#99ccff size=2>ZeroMemory(&amp;ddscaps, sizeof(ddscaps));<br>ddscaps.dwCaps = DDSCAPS_BACKBUFFER;<br>hRet = g_pDDSPrimary-&gt;GetAttachedSurface(&amp;ddscaps, &amp;g_pDDSBack);<br>if (hRet != DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp; // g_pDDSBack points to the back buffer.<br>}<br>else<br>{<br>&nbsp;&nbsp;&nbsp; return FALSE;<br>}</font><font face=Tahoma size=2><br><br>如果IDirectDrawSurface7::GetAttachedSurface调用成功,g_pDDSBack参数将指向缓存区.</font></p>
                                    <p><font face=Tahoma size=2>&nbsp;</font></p>
                                    <p><font face=Tahoma size=2>step5:在平面上输出<br>在主平面(primary surface)和后台缓冲(back buffer)创建完成后,例子DDEx1用windows标准GDI函数输出了一些文本在缓冲上.如下:<br><br></font><font face=宋体 color=#99ccff size=2>if (g_pDDSBack-&gt;GetDC(&amp;hdc) == DD_OK)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetBkColor(hdc, RGB(0, 0, 255));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetTextColor(hdc, RGB(255, 255, 0));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (phase)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetClientRect(hWnd, &amp;rc);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetTextExtentPoint(hdc, szMsg, lstrlen(szMsg), &amp;size);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut(hdc, (rc.right - size.cx) / 2, (rc.bottom - size.cy) / 2,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; szMsg, sizeof(szMsg) - 1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut(hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phase = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TextOut(hdc, 0, 0, szBackMsg, lstrlen(szBackMsg));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phase = 1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_pDDSBack-&gt;ReleaseDC(hdc);<br>}</font></p>
                                    <p><font face=Tahoma size=2>这个例子使用the IDirectDrawSurface7::GetDC方法获得设备上下文的句柄,并且,为了准备写入,将缓冲上锁.如果你不准备用需要设备上下文句柄的windows函数,你可以使用IDirectDrawSurface7::Lock&nbsp; IDirectDrawSurface7::Unlock方法加解锁.<br>接下来,phase变量决定了应该输出到主缓存消息(primary buffer message)还是后台缓存消息(back buffer message).如果phase=1,输出<br>主缓存消息,且设phase=0.如果phase=0,输出后台缓存消息,且设phase=1.<br>当消息输出到缓存区后,用IDirectDrawSurface7::ReleaseDC 方法将缓存区解锁.<br>对创建平面的内存上锁,是保证你的程序和系统不能同时对此内存进行存取.这防止你写入"平面"内存事发生错误.另外,不对"平面"内存解锁,你的程序将无法翻转平面.<br>平面被加锁之后,例子中用了标准windowsGDI函数:SetBkColor设置背景色,SetTextColor设置在背景上显示的字的颜色,用TextOut在"表面"上输出文字和背景色.<br>当文字被输出到缓存之后,例子应用IDirectDrawSurface7::ReleaseDC方法解锁"表面"并且释放句柄.不论在什么时候你的程序完成了对缓存的写入,一定要调用IDirectDrawSurface7::ReleaseDC 或IDirectDrawSurface7::Unlock之一,具体用哪个,由你的程序而定.不解锁,你的程序将不能翻转平面.<br>注意:用IDirectDrawSurface7::Unlock对"平面"解锁后,指向"平面"的指针将会无效.你必须再用IDirectDrawSurface7::lock去获得一个有效的指针.</font></p>
                                    <p><font face=Tahoma size=2>&nbsp;</font></p>
                                    <p><font face=Tahoma size=2>step:6 翻转平面<br>在DDEx1中,WM_TIMER消息引发从缓存到主平面的翻转.当"平面"内存解锁后,你就可以用IDirectDrawSurface7::Flip方法实现从缓存到主平面的翻转.如下:<br><br></font><font face=宋体 color=#99ccff size=2>case WM_TIMER:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Update and flip surfaces<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (g_bActive &amp;&amp; TIMER_ID == wParam)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UpdateFrame(hWnd);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (TRUE)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hRet = g_pDDSPrimary-&gt;Flip(NULL, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hRet == DD_OK)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hRet == DDERR_SURFACELOST)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hRet = g_pDDSPrimary-&gt;Restore();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hRet != DD_OK)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hRet != DDERR_WASSTILLDRAWING)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</font></p>
                                    <p><font face=Tahoma size=2>在例子中,g_pDDSPrimary参数指示主平面和与他连接的缓存.当IDirectDrawSurface7::Flip被调用,前后平面将会交换(只是交换指针,没有实际的数据交换).如果翻转成功,返回DD_OK,跳出循环.<br>如果翻转返回的是DDERR_SURFACELOST值,就试图用IDirectDrawSurface7::Restore 方法保存平面.如果保存成功,程序循环到调用IDirectDrawSurface7::Flip,再试一次.如果保存不成功,程序跳出循环,返回一个错误.<br>注意:当你调用IDirectDrawSurface7::Flip 时,翻转动作并不能马上完成.如果,前一个翻转动作还没有完成,IDirectDrawSurface7::Flip 会返回DDERR_WASSTILLDRAWING.在这个例子中,IDirectDrawSurface7::Flip会一直调用直到返回DD_OK.</font></p>
                                    <p><font face=Tahoma size=2><br>step7:释放DirectDraw对象<br>当你按下F12键时,例子DDEx1将在退出程序前处理WM_DESTROY消息.这个消息将调用ReleaseAllObjects函数,这个函数包括了多个Release调用.像下面一样:<br><br></font><font face=宋体 color=#99ccff size=2>static void<br>ReleaseAllObjects(void)<br>{<br>&nbsp;&nbsp;&nbsp; if (g_pDD != NULL)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (g_pDDSPrimary != NULL)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_pDDSPrimary-&gt;Release();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_pDDSPrimary = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_pDD-&gt;Release();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_pDD = NULL;<br>&nbsp;&nbsp;&nbsp; }<br>}</font><font face=Tahoma size=2><br><br>这个程序检测DirectDraw对象的指针g_pDD和DirectDraw平面对象的指针g_pDDSPrimary是否为NULL.然后,调用IDirectDrawSurface7::Release方法令DirectDraw平面对象的reference count(可以认为是创建的对象的数目)数减1,这使得reference count减为0,DirectDraw平面对象就释放了.然后,还需将他的指针值设为NULL.接下来,程序调用IDirectDraw7::Release,同样是令DirectDraw的reference count减1,然后然后....全销毁.</font><font face=Tahoma color=#c0c0c0 size=2><br>　</font></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </div>
                        </td>
                    </tr>
                    </center>
                    <tr>
                        <td width="100%" bgColor=#1d2532><font face=Tahoma size=2>　</font></td>
                    </tr>
                    <tr>
                        <td width="100%"><font face=Tahoma size=2>&nbsp;</font></td>
                    </tr>
                </tbody>
            </table>
            </div>
            </td>
        </tr>
        <tr>
            <td width="100%" colSpan=3></td>
        </tr>
    </tbody>
</table>
</p>
<img src ="http://www.cppblog.com/iniwf/aggbug/85697.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-05-25 14:29 <a href="http://www.cppblog.com/iniwf/archive/2009/05/25/85697.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Various methods for capturing the screen</title><link>http://www.cppblog.com/iniwf/archive/2009/03/16/76788.html</link><dc:creator>iniwf</dc:creator><author>iniwf</author><pubDate>Mon, 16 Mar 2009 14:51:00 GMT</pubDate><guid>http://www.cppblog.com/iniwf/archive/2009/03/16/76788.html</guid><wfw:comment>http://www.cppblog.com/iniwf/comments/76788.html</wfw:comment><comments>http://www.cppblog.com/iniwf/archive/2009/03/16/76788.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/iniwf/comments/commentRss/76788.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/iniwf/services/trackbacks/76788.html</trackback:ping><description><![CDATA[<a href="http://www.codeproject.com/KB/dialog/screencap.aspx">http://www.codeproject.com/KB/dialog/screencap.aspx</a><br><br>
<ul class=download>
    <li><a href="http://www.codeproject.com/KB/dialog/screencap/ScreenCap.zip"><u><font color=#0000ff>Download GDI source code - 72.1 Kb</font></u></a>
    <li><a href="http://www.codeproject.com/KB/dialog/screencap/ScreenCapDx.zip"><u><font color=#0000ff>Download DirectX source code - 78.7 Kb</font></u></a>
    <li><a href="http://www.codeproject.com/KB/dialog/screencap/WMEncScrnCap.zip"><u><font color=#0000ff>Download WMEncoder source code - 59.7 Kb</font></u></a> </li>
</ul>
<h2>Contents</h2>
<ul>
    <li><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#Introduction:"><u><font color=#800080>Introduction</font></u></a>
    <li><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#Capture It the GDI way:"><u><font color=#800080>Capture it the GDI way</font></u></a>
    <li><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#And The DirectX way of doing it :"><u><font color=#800080>And the DirectX way of doing it</font></u></a>
    <li><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#Windows Media API for Capturing the Screen :"><u><font color=#800080>Capturing the screen with Windows Media API</font></u></a> </li>
</ul>
<h2><a name=Introduction:>Introduction</a></h2>
<p>Some times, we want to capture the contents of the entire screen programmatically. The following explains how it can be done. Typically, the immediate options we have, among others, are using <em>GDI</em> and/or <em>DirectX</em>. Another option that is worth considering is <em>Windows Media API</em>. Here, we would consider each of them and see how they can be used for our purpose. In each of these approaches, once we get the screenshot into our application defined memory or bitmap, we can use it in generating a movie. Refer to the article <a href="http://www.geocities.com/krishnapg/createmovie.html" target=_blank><u><font color=#0000ff>Create Movie From HBitmap</font></u></a> for more details about creating movies from bitmap sequences programmatically.</p>
<h2><a name="Capture It the GDI way:">Capture it the GDI way</a></h2>
<p>When performance is not an issue and when all that we want is just a snapshot of the desktop, we can consider the GDI option. This mechanism is based on the simple principle that the desktop is also a window - that is it has a window Handle (<code>HWND</code>) and a device context (DC). If we can get the device context of the desktop to be captured, we can just <code>blit</code> those contents to our application defined device context in the normal way. And getting the device context of the desktop is pretty straightforward if we know its window handle - which can be achieved through the function <code>GetDesktopWindow()</code>. Thus, the steps involved are:</p>
<ol>
    <li>Acquire the Desktop window handle using the function <code>GetDesktopWindow()</code>;
    <li>Get the DC of the desktop window using the function <code>GetDC()</code>;
    <li>Create a compatible DC for the Desktop DC and a compatible bitmap to select into that compatible DC. These can be done using <code>CreateCompatibleDC()</code> and <code>CreateCompatibleBitmap()</code>; selecting the bitmap into our DC can be done with <code>SelectObject()</code>;
    <li>Whenever you are ready to capture the screen, just <code>blit</code> the contents of the Desktop DC into the created compatible DC - that's all - you are done. The compatible bitmap we created now contains the contents of the screen at the moment of the capture.
    <li>Do not forget to release the objects when you are done. Memory is precious (for the other applications). </li>
</ol>
<h3>Example</h3>
<div class=SmallText id=premain0 style="WIDTH: 100%"><img id=preimg0 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="0"><span id=precollapse0 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="0"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="0"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre0 style="MARGIN-TOP: 0px">Void CaptureScreen()
{
<span class=code-keyword>int</span> nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
<span class=code-keyword>int</span> nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC,
nScreenWidth, nScreenHeight);
SelectObject(hCaptureDC,hCaptureBitmap);
BitBlt(hCaptureDC,<span class=code-digit>0</span>,<span class=code-digit>0</span>,nScreenWidth,nScreenHeight,
hDesktopDC,<span class=code-digit>0</span>,<span class=code-digit>0</span>,SRCCOPY|CAPTUREBLT);
SaveCapturedBitmap(hCaptureBitmap); <span class=code-comment>//</span><span class=code-comment>Place holder - Put your code
</span>                                <span class=code-comment>//</span><span class=code-comment>here to save the captured image to disk
</span>    ReleaseDC(hDesktopWnd,hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);
}</pre>
<p>In the above code snippet, the function <code>GetSystemMetrics()</code> returns the screen width when used with <code>SM_CXSCREEN</code>, and returns the screen height when called with <code>SM_CYSCREEN</code>. Refer to the accompanying source code for details of how to save the captured bitmap to the disk and how to send it to the clipboard. Its pretty straightforward. The source code implements the above technique for capturing the screen contents at regular intervals, and creates a movie out of the captured image sequences.</p>
<h2><a name="And The DirectX way of doing it :">And the DirectX way of doing it</a></h2>
<p>Capturing the screenshot with DirectX is a pretty easy task. DirectX offers a neat way of doing this.</p>
<p>Every DirectX application contains what we call a buffer, or a surface to hold the contents of the video memory related to that application. This is called the back buffer of the application. Some applications might have more than one back buffer. And there is another buffer that every application can access by default - the front buffer. This one, the front buffer, holds the video memory related to the desktop contents, and so essentially is the screen image.</p>
<p>By accessing the front buffer from our DirectX application, we can capture the contents of the screen at that moment.</p>
<p>Accessing the front buffer from the DirectX application is pretty easy and straightforward. The interface <code>IDirect3DDevice9</code> provides the <code>GetFrontBufferData()</code> method that takes a <code>IDirect3DSurface9</code> object pointer and copies the contents of the front buffer onto that surface. The <code>IDirect3DSurfce9</code> object can be generated by using the method <code>IDirect3DDevice8::CreateOffscreenPlainSurface()</code>. Once the screen is captured onto the surface, we can use the function <code>D3DXSaveSurfaceToFile()</code> to save the surface directly to the disk in bitmap format. Thus, the code to capture the screen looks as follows:</p>
<div class=SmallText id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="1"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre1 style="MARGIN-TOP: 0px"><span class=code-keyword>extern</span> IDirect3DDevice9* g_pd3dDevice;
Void CaptureScreen()
{
IDirect3DSurface9* pSurface;
g_pd3dDevice-<span class=code-keyword>&gt;</span>CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight,
D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &amp;pSurface, NULL);
g_pd3dDevice-<span class=code-keyword>&gt;</span>GetFrontBufferData(<span class=code-digit>0</span>, pSurface);
D3DXSaveSurfaceToFile(<span class=code-string>"</span><span class=code-string>Desktop.bmp"</span>,D3DXIFF_BMP,pSurface,NULL,NULL);
pSurface-<span class=code-keyword>&gt;</span>Release();
}</pre>
<p>In the above, <code>g_pd3dDevice</code> is an <code>IDirect3DDevice9</code> object, and has been assumed to be properly initialized. This code snippet saves the captured image onto the disk directly. However, instead of saving to disk, if we just want to operate on the image bits directly - we can do so by using the method <code>IDirect3DSurface9::LockRect()</code>. This gives a pointer to the surface memory - which is essentially a pointer to the bits of the captured image. We can copy the bits to our application defined memory and can operate on them. The following code snippet presents how the surface contents can be copied into our application defined memory:</p>
<div class=SmallText id=premain2 style="WIDTH: 100%"><img id=preimg2 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="2"><span id=precollapse2 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="2"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="2"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre2 style="MARGIN-TOP: 0px"><span class=code-keyword>extern</span> <span class=code-keyword>void</span>* pBits;
<span class=code-keyword>extern</span> IDirect3DDevice9* g_pd3dDevice;
IDirect3DSurface9* pSurface;
g_pd3dDevice-<span class=code-keyword>&gt;</span>CreateOffscreenPlainSurface(ScreenWidth, ScreenHeight,
D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH,
&amp;pSurface, NULL);
g_pd3dDevice-<span class=code-keyword>&gt;</span>GetFrontBufferData(<span class=code-digit>0</span>, pSurface);
D3DLOCKED_RECT lockedRect;
pSurface-<span class=code-keyword>&gt;</span>LockRect(&amp;lockedRect,NULL,
D3DLOCK_NO_DIRTY_UPDATE|
D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)));
<span class=code-keyword>for</span>( <span class=code-keyword>int</span> i=0 ; i <span class=code-keyword>&lt;</span> ScreenHeight ; i++)
{
memcpy( (<span class=code-SDKkeyword>BYTE</span>*) pBits + i * ScreenWidth * BITSPERPIXEL / <span class=code-digit>8</span> ,
(<span class=code-SDKkeyword>BYTE</span>*) lockedRect.pBits + i* lockedRect.Pitch ,
ScreenWidth * BITSPERPIXEL / <span class=code-digit>8</span>);
}
g_pSurface-<span class=code-keyword>&gt;</span>UnlockRect();
pSurface-<span class=code-keyword>&gt;</span>Release();</pre>
<p>In the above, <code>pBits</code> is a <code><span class=code-keyword>void</span>*</code>. Make sure that we have allocated enough memory before copying into <code>pBits</code>. A typical value for <code>BITSPERPIXEL</code> is 32 bits per pixel. However, it may vary depending on your current monitor settings. The important point to note here is that the width of the surface is not same as the captured screen image width. Because of the issues involved in the memory alignment (memory aligned to word boundaries are assumed to be accessed faster compared to non aligned memory), the surface might have added additional stuff at the end of each row to make them perfectly aligned to the word boundaries. The <code>lockedRect.Pitch</code> gives us the number of bytes between the starting points of two successive rows. That is, to advance to the correct point on the next row, we should advance by <code>Pitch</code>, not by <code>Width</code>. You can copy the surface bits in reverse, using the following:</p>
<div class=SmallText id=premain3 style="WIDTH: 100%"><img id=preimg3 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="3"><span id=precollapse3 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="3"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="3"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre3 style="MARGIN-TOP: 0px"><span class=code-keyword>for</span>( <span class=code-keyword>int</span> i=0 ; i <span class=code-keyword>&lt;</span> ScreenHeight ; i++)
{
memcpy((<span class=code-SDKkeyword>BYTE</span>*) pBits +( ScreenHeight - i - <span class=code-digit>1</span>) *
ScreenWidth * BITSPERPIXEL/8 ,
(<span class=code-SDKkeyword>BYTE</span>*) lockedRect.pBits + i* lockedRect.Pitch ,
ScreenWidth* BITSPERPIXEL/8);
}</pre>
<p>This may come handy when you are converting between top-down and bottom-up bitmaps.</p>
<p>While the above technique of <code>LockRect()</code> is one way of accessing the captured image content on <code>IDirect3DSurface9</code>, we have another more sophisticated method defined for <code>IDirect3DSurface9</code>, the <code>GetDC()</code> method. We can use the <code>IDirect3DSurface9::GetDC()</code> method to get a GDI compatible device context for the DirectX image surface, which makes it possible to directly <code>blit</code> the surface contents to our application defined DC. Interested readers can explore this alternative.</p>
<p>The sample source code provided with this article implements the technique of copying the contents of an off-screen plain surface onto a user created bitmap for capturing the screen contents at regular intervals, and creates a movie out of the captured image sequences.</p>
<p>However, a point worth noting when using this technique for screen capture is the caution mentioned in the documentation: The <code>GetFrontBufferData()</code> is a slow operation <em>by design</em>, and should not be considered for use in performance-critical applications. Thus, the GDI approach is preferable over the DirectX approach in such cases.</p>
<h2><a name="Windows Media API for Capturing the Screen :">Windows Media API for capturing the screen</a></h2>
<p>Windows Media 9.0 supports screen captures using the Windows Media Encoder 9 API. It includes a codec named <em>Windows Media Video 9 Screen codec</em> that has been specially optimized to operate on the content produced through screen captures. The Windows Media Encoder API provides the interface <code>IWMEncoder2</code> which can be used to capture the screen content efficiently.</p>
<p>Working with the Windows Media Encoder API for screen captures is pretty straightforward. First, we need to start with the creation of an <code>IWMEncoder2</code> object by using the <code>CoCreateInstance()</code> function. This can be done as:</p>
<div class=SmallText id=premain4 style="WIDTH: 100%"><img id=preimg4 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="4"><span id=precollapse4 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="4"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="4"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre4 style="MARGIN-TOP: 0px">IWMEncoder2* g_pEncoder=NULL;
CoCreateInstance(CLSID_WMEncoder,NULL,CLSCTX_INPROC_SERVER,
IID_IWMEncoder2,(<span class=code-keyword>void</span>**)&amp;g_pEncoder);</pre>
<p>The <code>Encoder</code> object thus created contains all the operations for working with the captured screen data. However, in order to perform its operations properly, the encoder object depends on the settings defined in what is called a profile. A profile is nothing but a file containing all the settings that control the encoding operations. We can also create custom profiles at runtime with various customized options, such as codec options etc., depending on the nature of the captured data. To use a profile with our screen capture application, we create a custom profile based on the <em>Windows Media Video 9 Screen codec</em>. Custom profile objects have been supported with the interface <code>IWMEncProfile2</code>. We can create a custom profile object by using the <code>CoCreateInstance()</code> function as:</p>
<div class=SmallText id=premain5 style="WIDTH: 100%"><img id=preimg5 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="5"><span id=precollapse5 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="5"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="5"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre5 style="MARGIN-TOP: 0px">IWMEncProfile2* g_pProfile=NULL;
CoCreateInstance(CLSID_WMEncProfile2,NULL,CLSCTX_INPROC_SERVER,
IID_IWMEncProfile2,(<span class=code-keyword>void</span>**)&amp;g_pProfile);</pre>
<p>We need to specify the target audience for the encoder in the profile. Each profile can hold multiple number of audience configurations, which are objects of the interface <code>IWMEncAudienceObj</code>. Here, we use one audience object for our profile. We create the audience object for our profile by using the method <code>IWMEncProfile::AddAudience()</code>, which would return a pointer to <code>IWMEncAudienceObj</code> which can then be used for configurations such as video codec settings (<code>IWMEncAudienceObj::put_VideoCodec()</code>), video frame size settings (<code>IWMEncAudienceObj::put_VideoHeight()</code> and <code>IWMEncAudienceObj::put_VideoWidth()</code>) etc. For example, we set the video codec to be <em>Windows Media Video 9 Screen codec</em> as:</p>
<div class=SmallText id=premain6 style="WIDTH: 100%"><img id=preimg6 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="6"><span id=precollapse6 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="6"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="6"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre6 style="MARGIN-TOP: 0px"><span class=code-keyword>extern</span> IWMEncAudienceObj* pAudience;
<span class=code-preprocessor>#define</span> VIDEOCODEC MAKEFOURCC(<span class=code-string>'</span><span class=code-string>M'</span>,<span class=code-string>'</span><span class=code-string>S'</span>,<span class=code-string>'</span><span class=code-string>S'</span>,<span class=code-string>'</span><span class=code-string>2'</span>)
<span class=code-comment>//</span><span class=code-comment>MSS2 is the fourcc for the screen codec
</span>
<span class=code-keyword>long</span> lCodecIndex=-<span class=code-digit>1</span>;
g_pProfile-<span class=code-keyword>&gt;</span>GetCodecIndexFromFourCC(WMENC_VIDEO,VIDEOCODEC,
&amp;lCodecIndex); <span class=code-comment>//</span><span class=code-comment>Get the Index of the Codec
</span>pAudience-<span class=code-keyword>&gt;</span>put_VideoCodec(<span class=code-digit>0</span>,lCodecIndex);</pre>
<p>The fourcc is a kind of unique identifier for each codec in the world. The fourcc for the <em>Windows Media Video 9 Screen codec </em>is MSS2. The <code>IWMEncAudienceObj::put_VideoCodec()</code> accepts the profile index as the input to recognize a particular profile - which can be obtained by using the method <code>IWMEncProfile::GetCodecIndexFromFourCC()</code>.</p>
<p>Once we have completed configuring the profile object, we can choose that profile into our encoder by using the method <code>IWMEncSourceGroup :: put_Profile()</code> which is defined on the <em>source group</em> objects of the encoder. A source group is a collection of <em>sources</em> where each source might be a video stream or audio stream or HTML stream etc. Each encoder object can work with many source groups from which it get the input data. Since our screen capture application uses only a video stream, our encoder object need to have one source group with a single source, the video source, in it. This single video source needs to configured to use the <em>Screen Device </em>as the input source, which can be done by using the method <code>IWMEncVideoSource2::SetInput(BSTR)</code> as:</p>
<div class=SmallText id=premain7 style="WIDTH: 100%"><img id=preimg7 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="7"><span id=precollapse7 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="7"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="7"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre7 style="MARGIN-TOP: 0px"><span class=code-keyword>extern</span> IWMEncVideoSource2* pSrcVid;
pSrcVid-<span class=code-keyword>&gt;</span>SetInput(CComBSTR(<span class=code-string>"</span><span class=code-string>ScreenCap://ScreenCapture1"</span>);</pre>
<p>The destination output can be configured to save into a video file (<em>wmv movie</em>) by using the method <code>IWMEncFile::put_LocalFileName()</code> which requires an <code>IWMEncFile</code> object. This <code>IWMEncFile</code> object can be obtained by using the method <code>IWMEncoder::get_File()</code> as:</p>
<div class=SmallText id=premain8 style="WIDTH: 100%"><img id=preimg8 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="8"><span id=precollapse8 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="8"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="8"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre8 style="MARGIN-TOP: 0px">IWMEncFile* pOutFile=NULL;
g_pEncoder-<span class=code-keyword>&gt;</span>get_File(&amp;pOutFile);
pOutFile-<span class=code-keyword>&gt;</span>put_LocalFileName(CComBSTR(szOutputFileName);</pre>
<p>Now, once all the necessary configurations have been done on the encoder object, we can use the method <code>IWMEncoder::Start()</code> to start capturing the screen. The methods <code>IWMEncoder::Stop()</code> and <code>IWMEncoder::Pause</code> might be used for stopping and pausing the capture.</p>
<p>While this deals with full screen capture, we can alternately select the regions of capture by adjusting the properties of input video source stream. For this, we need to use the <code>IPropertyBag</code> interface of the <code>IWmEnVideoSource2</code> object as:</p>
<div class=SmallText id=premain9 style="WIDTH: 100%"><img id=preimg9 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="9"><span id=precollapse9 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="9"> Collapse</span><img style="MARGIN-LEFT: 35px" height=16 src="http://www.codeproject.com/images/copy_16.png" width=16><a href="http://www.codeproject.com/KB/dialog/screencap.aspx#" preid="9"><u><font color=#800080> Copy Code</font></u></a></div>
<pre id=pre9 style="MARGIN-TOP: 0px"><span class=code-preprocessor>#define</span> WMSCRNCAP_WINDOWLEFT CComBSTR(<span class=code-string>"</span><span class=code-string>Left"</span>)
<span class=code-preprocessor>#define</span> WMSCRNCAP_WINDOWTOP CComBSTR(<span class=code-string>"</span><span class=code-string>Top"</span>)
<span class=code-preprocessor>#define</span> WMSCRNCAP_WINDOWRIGHT CComBSTR(<span class=code-string>"</span><span class=code-string>Right"</span>)
<span class=code-preprocessor>#define</span> WMSCRNCAP_WINDOWBOTTOM CComBSTR(<span class=code-string>"</span><span class=code-string>Bottom"</span>)
<span class=code-preprocessor>#define</span> WMSCRNCAP_FLASHRECT CComBSTR(<span class=code-string>"</span><span class=code-string>FlashRect"</span>)
<span class=code-preprocessor>#define</span> WMSCRNCAP_ENTIRESCREEN CComBSTR(<span class=code-string>"</span><span class=code-string>Screen"</span>)
<span class=code-preprocessor>#define</span> WMSCRNCAP_WINDOWTITLE CComBSTR(<span class=code-string>"</span><span class=code-string>WindowTitle"</span>)
<span class=code-keyword>extern</span> IWMEncVideoSource2* pSrcVid;
<span class=code-keyword>int</span> nLeft, nRight, nTop, nBottom;
pSrcVid-<span class=code-keyword>&gt;</span>QueryInterface(IID_IPropertyBag,(<span class=code-keyword>void</span>**)&amp;pPropertyBag);
CComVariant varValue = <span class=code-keyword>false</span>;
pPropertyBag-<span class=code-keyword>&gt;</span>Write(WMSCRNCAP_ENTIRESCREEN,&amp;varValue);
varValue = nLeft;
pPropertyBag-<span class=code-keyword>&gt;</span>Write( WMSCRNCAP_WINDOWLEFT, &amp;varValue );
varValue = nRight;
pPropertyBag-<span class=code-keyword>&gt;</span>Write( WMSCRNCAP_WINDOWRIGHT, &amp;varValue );
varValue = nTop;
pPropertyBag-<span class=code-keyword>&gt;</span>Write( WMSCRNCAP_WINDOWTOP, &amp;varValue );
varValue = nBottom;
pPropertyBag-<span class=code-keyword>&gt;</span>Write( WMSCRNCAP_WINDOWBOTTOM, &amp;varValue );</pre>
<p>The accompanied source code implements this technique for capturing the screen. One point that might be interesting, apart from the nice quality of the produced output movie, is that in this, the mouse cursor is also captured. (By default, GDI and DirectX are unlikely to capture the mouse cursor).</p>
<p>Note that your system needs to be installed with Windows Media 9.0 SDK components to create applications using the Window Media 9.0 API.</p>
<p>To run your applications, end users must install the Windows Media Encoder 9 Series. When you distribute applications based on the Windows Media Encoder SDK, you must also include the Windows Media Encoder software, either by redistributing Windows Media Encoder in your setup, or by requiring your users to install Windows Media Encoder themselves.</p>
<p>The Windows Media Encoder 9.0 can be downloaded from:</p>
<ul>
    <li><a href="http://www.microsoft.com/windows/windowsmedia/9series/encoder/default.aspx" target=_blank><u><font color=#0000ff>Windows Media Encoder</font></u></a></li>
</ul>
<h2>Conclusion</h2>
<p>All the variety of techniques discussed above are aimed at a single goal - capturing the contents of the screen. However, as can be guessed easily, the results vary depending upon the particular technique that is being employed in the program. If all that we want is just a random snapshot occasionally, the GDI approach is a good choice, given its simplicity. However, using Windows Media would be a better option if we want more professional results. One point worth noting is, the quality of the content captured through these mechanisms might depend on the settings of the system. For example, disabling hardware acceleration (Desktop properties | Settings | Advanced | Troubleshoot) might drastically improve the overall quality and performance of the capture application.</p>
<!-- Article Ends --><!-- Main Page Contents End -->
<form id=aspnetForm style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px" name=aspnetForm action=screencap.aspx method=post>
    <div><input id=__VIEWSTATE type=hidden value=/wEPDwULLTEwMDUyNjYzMjgPZBYCZg9kFgQCCw9kFgYCAw8PFgIeB1Zpc2libGVnZGQCCQ8PFgIfAGdkZAIMDw8WAh8AZ2RkAgwPZBYKAgcPZBYOAgEPZBYCZg8WAh4LXyFJdGVtQ291bnRmZAIDD2QWCmYPDxYCHgtOYXZpZ2F0ZVVybAUnL0tCL2RpYWxvZy9zY3JlZW5jYXAuYXNweD9kaXNwbGF5PVByaW50ZGQCAQ8PFgIfAgUlL3NjcmlwdC9BcnRpY2xlcy9SZXBvcnQuYXNweD9haWQ9NTA1MWRkAgIPDxYCHwBoZGQCAw8PFgIfAGhkZAIFDw8WAh8CBTAvc2NyaXB0L2NvbW1vbi9UZWxsRnJpZW5kLmFzcHg/b2J0aWQ9MiZvYmlkPTUwNTFkZAIFD2QWBAIBD2QWAgIBDw8WAh4EVGV4dAUaNzMgdm90ZXMgZm9yIHRoaXMgQXJ0aWNsZS5kZAIGD2QWAmYPZBYEAgEPDxYEHwMFEFBvcHVsYXJpdHk6IDguNzcfAgUpL3NjcmlwdC9BcnRpY2xlcy9Ub3BBcnRpY2xlcy5hc3B4P3RhX3NvPTFkZAIFDxYCHwMFHFJhdGluZzogPGI+NC43MDwvYj4gb3V0IG9mIDVkAhkPZBYKAgEPZBYEAgEPFgIeCWlubmVyaHRtbAW/ATxwPlRoaXMgYXJ0aWNsZSwgYWxvbmcgd2l0aCBhbnkgYXNzb2NpYXRlZCBzb3VyY2UgY29kZSBhbmQgZmlsZXMsIGlzIGxpY2Vuc2VkIHVuZGVyIDxhIGhyZWY9Imh0dHA6Ly93d3cub3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvbGdwbC1saWNlbnNlLnBocCI+VGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZTwvYT48L3A+ZAICD2QWAgIBDxBkZBYAZAIFDxYCHwECAWQCBw8WAh8DBcEIPGgyPk90aGVyIHBvcHVsYXIgRGlhbG9ncyBhbmQgV2luZG93cyBhcnRpY2xlczo8L2gyPjx1bD48bGk+PGEgaHJlZj0iL0tCL2RpYWxvZy9kaWFsb2dhcHB0dXRlLmFzcHgiPkEgQmVnaW5uZXJzIEd1aWRlIHRvIERpYWxvZyBCYXNlZCBBcHBsaWNhdGlvbnMgLSBQYXJ0IE9uZTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPkEgc3RlcCBieSBzdGVwIHR1dG9yaWFsIHNob3dpbmcgaG93IHRvIGNyZWF0ZSB5b3VyIGZpcnN0IHdpbmRvd3MgcHJvZ3JhbSB1c2luZyBNRkM8L2Rpdj48L2xpPjxsaT48YSBocmVmPSIvS0IvZGlhbG9nL2xheW91dG1nci5hc3B4Ij5MYXlvdXQgTWFuYWdlciBmb3IgRGlhbG9ncywgRm9ybXZpZXdzLCBEaWFsb2dCYXJzIGFuZCBQcm9wZXJ0eVBhZ2VzPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+QSBmcmFtZXdvcmsgdG8gcHJvdmlkZSBhdXRvbWF0aWMgbGF5b3V0IGNvbnRyb2wgZm9yIGRpYWxvZ3MgYW5kIGZvcm1zPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL2RpYWxvZy9lYXN5c2l6ZS5hc3B4Ij5FYXN5U2l6ZSAtIERpYWxvZyByZXNpemluZyBpbiBubyB0aW1lITwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPkFuIGVhc3kgd2F5IHRvIHBvc2l0aW9uIGNvbnRyb2xzIGluIHJlc2l6YWJsZSBkaWFsb2dzIG9yIHByb3BlcnR5IHBhZ2VzIHVzaW5nIGp1c3QgYSBmZXcgbWFjcm9zPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL2RpYWxvZy94bWVzc2FnZWJveC5hc3B4Ij5YTWVzc2FnZUJveCAtIEEgcmV2ZXJzZS1lbmdpbmVlcmVkIE1lc3NhZ2VCb3goKTwvYT48ZGl2IGNsYXNzPSJTbWFsbFRleHQiPkEgcmV2ZXJzZS1lbmdpbmVlcmVkIG5vbi1NRkMgTWVzc2FnZUJveCgpIHRoYXQgaW5jbHVkZXMgY3VzdG9tIGNoZWNrYm94ZXMuPC9kaXY+PC9saT48bGk+PGEgaHJlZj0iL0tCL2RpYWxvZy92aXN1YWxmeC5hc3B4Ij5BIFZpc3VhbCBGcmFtZXdvcmsgKFZpZXdzLCBUYWJzIGFuZCBTcGxpdHRlcnMpPC9hPjxkaXYgY2xhc3M9IlNtYWxsVGV4dCI+Q3JlYXRpbmcgU0RJL01ESSBhcHBsaWNhdGlvbnMgd2l0aCBzcGxpdHRlciBhbmQgdGFiIHdpbmRvd3M8L2Rpdj48L2xpPjwvdWw+ZAIJDw8WAh8AZ2RkAg0PZBYCZg9kFgICAQ9kFgJmD2QWAgIJDxYCHwBoFgICAQ8QZGQWAGQCGw8PFgIfAGdkZAIdDw8WAh8AZ2RkAiUPFgIfAGhkAgkPDxYCHwIFJi9zY3JpcHQvQXJ0aWNsZXMvQXJ0aWNsZS5hc3B4P2FpZD01MDUxZGQCDw8WAh8DBQsxOSBTZXAgMjAwNmQCEQ8PFgQfAwUOU21pdGhhIFZpamF5YW4fAgUqL3NjcmlwdC9NZW1iZXJzaGlwL1Byb2ZpbGVzLmFzcHg/bWlkPTI4OTcwZGQCEw8WAh8DBSVDb3B5cmlnaHQgMjAwMyBieSBHb3BhbGFrcmlzaG5hIFBhbGVtZGRodvpkYJGRpR1Ml3z4nKeHylUtTA== name=__VIEWSTATE> </div>
    <h2>License</h2>
    <div id=ctl00_LicenseTerms>
    <p>This article, along with any associated source code and files, is licensed under <a href="http://www.opensource.org/licenses/lgpl-license.php"><u><font color=#0000ff>The GNU Lesser General Public License</font></u></a></p>
    </div>
    <h2>About the Author</h2>
    <table cellSpacing=5 cellPadding=0 width="100%" border=0>
        <tbody>
            <tr vAlign=top>
                <td id=ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberPhotoTable style="WIDTH: 155px" vAlign=top><strong><a id=ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberProfileLink href="http://www.codeproject.com/script/Membership/Profiles.aspx?mid=251226"><u><font color=#0000ff>Gopalakrishna Palem</font></u></a></strong><br><br>
                <center></center><br><span class=SmallText id=ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberType></span></td>
                <td><br></td>
            </tr>
        </tbody>
    </table>
</form>
<img src ="http://www.cppblog.com/iniwf/aggbug/76788.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/iniwf/" target="_blank">iniwf</a> 2009-03-16 22:51 <a href="http://www.cppblog.com/iniwf/archive/2009/03/16/76788.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>