写DIRECTDRAW中的第一个例子

 

呵呵,今天早上一起来就听到老婆的手机不行了,唉。我也想换一个,怎么舍不得咯。

 

不管了,我今天要学DirectDraw了。一定要在一周之内做完。

 

首先用的第一个例子是directdraw.chm 里面的一个DirectDraw入门程序

  1. 选择Link栏,在Object/Library modules中添入“Ddraw.lib”。
  • 请注意:这一步骤是将DirectDraw的静态连接库文件连接到工程中,否则,程序虽然可以正常编译,但是在连接时会产生一个“unresolved external symbol”(没有定义的外部符号)的错误。在以后所有的DirectDraw程序中,都必须将与你所用到的DirectDraw组件相应的静态连接库添入到这个设置中。

我按照文档提示的来,并没有出现文档所提示的效果。有点郁闷,我只能往下看了。我昨天也调试了很久,没有调出来。我开始以为是TEXTOUT这个函数显示字符串的问题,但现在看来,又好像不是,我迷惑了。

 

函数调用顺序依次是这样的。

WinMain ----> InitWindow ----> InitDDraw ----> WinProc ----> FreeDDraw

WinMain:所有Win32应用程序的入口函数,它也是应用程序关闭时的出口,一个应用程序的全生命周期就是在它的控制之下。所以,确切的说,其它四个函数是被包括在WinMain之内的。消息循环也是在这个函数中启动。

InitWindow:初始化和创建一个与程序的HINSTANCE(实例句柄)相关联的主窗口,这个窗口的HWND(窗口句柄)在初始化DirectDraw环境时需要用到。

InitDDraw:初始化和创建DirectDraw对象,并执行一定的功能。它里面包括了创建DirectDraw对象,创建页面,设置显示模式,创建主页面,输出文字。

WinProc:是应用程序感知外来动作和产生反应的神经中枢,相当于人的大脑。这是程序中最主要的部件之一,它和在WinMain中所启动的消息循环是一起工作的。

FreeDDraw:释放DirectDraw的各种对象,以使其不再占用内存空间。

 

第一个是DirectDraw对象,表示显示硬件,它包括了显示器和显卡还有显存,用它来代表整个显示系统。

第二个是DirectDrawSurface对象,表示页面,你可以在大脑中把它想象成一张矩形的白纸,你可以在上面绘制图象。

这里所说的“对象”(Object),并不完全等同于C++中对象的概念,尽管它们使用的是同一个英文单词Object。这里的对象指的是COM,COM是Component Object Model 的缩写,代表“部件对象模型”,它在DirectX中贯穿始终,无处不是它的身影

 

HRESULT DirectDrawCreate(GUID FAR * lpGUID, LPDIRECTDRAW FAR * lplpDD, IUnknown FAR * pUnkOuter);  ---àThis function creates an instance of a DirectDraw object.

 

第一个参数是lpGUID:指向DirectDraw接口的全局唯一标志符(GUID:Global unique identify)的指针。在这里,我们给它NULL,表示我们将使用当前的DirectDraw接口。

第二个参数是lplpDD:这个参数是用来接受初始化成功的DirectDraw对象的地址。在这里,我们给它&lpdd。

第三个参数是pUnkOuter:千万不要追问这个参数是干嘛使的,如果你不想惹麻烦,就给它NULL吧。Microsoft的说明书上是这么写的“考虑到与将来的COM集合特性保持兼容,当前,不管怎样,如果这个参数不是NULL ,DirectDrawCreate将返回一个错误”。

所有的DirectDraw函数的返回值都是HRESULT类型,它是一个4字节(32位)的值,用来代表某个错误或警告。DirectDraw头文件中已经预定义了所有可能的返回值常量,仅函数返回成功的值是用 “DD_OK”表示,所有的错误值标志开头都为“DDERR”,如:

DDERR_DIRECTDRAWALREADYCREATED
DDERR_GENERIC
DDERR_OUTOFMEMORY

 

 

这个语句用来设置应用程序对操作系统的控制程度。它的原型如下:

HRESULT  SetCooperativeLevel( HWND hWnd, DWORD dwFlags )

 

IDirectDraw4::SetCooperativeLevel

The IDirectDraw4::SetCooperativeLevel method determines the top-level behavior of the application.  这个函数在MSDN2001里才有,2005里面已经找不到这个函数了。

 

第一个参数是hWnd,我们调用Win32的API函数GetActiveWindow获得应用程序主窗口的句柄,这将使DirectDraw对象与主窗口的消息挂上勾。

第二个参数是dwFlags,控制级的标志符。我们给它DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN,表示我们期望DirectDraw以独占和全屏方式工作。

这个函数有很多用法,而且它必须在创建DirectDraw对象之后,立即调用。你可以用它来设置应用程序是运行于全屏还是窗口模式,是独占还是共享模式。

 

问题,怎么才能不让它全屏显示 了。我感觉应该会有一个这样的函数。

 

 

if ( lpDD->SetDisplayMode( 640, 480, 8 ) != DD_OK) return FALSE;

显而易见,这是设置显示器的显示模式,它把显示模式设为640*480,8位色彩模式(即256色)。这是绝大多数显示器所能够支持的显示模式,所以我们不用担心它会出什么问题。在以后的例程中,我们将看到可以调用EnumDisplayModes()来列举出显示器所支持的所有显示模式。绝不要轻易尝试直接设置一个新的显示模式,而应从列举出的显示模式中选择,这也将在后续章节讲到。

·         要注意的是,只有当DirectDraw对象为独占访问的控制程度时才能改变显示器的显示模式,如果DirectDraw对象运行为窗口模式,调用该函数会返回一个错误。

 

4)创建主页面

然后的任务是要创建一个DirectDrawSurface对象。

DirectDrawSurface对象代表了一个页面。页面可以有很多种表现形式,它既可以是可见的(屏幕的一部分或全部),称之为主页面(Primary Surface);也可以是作换页用的不可见页面,称之后台缓存(Back Buffer),在换页后,它成为可见;还有一种始终不可见的,称之为离屏页面(Off-screen Surface),用它来存储图象。其中,最重要的页面是主页面,每个DirectDraw应用程序都必须创建至少一个主页面,用它来代表屏幕上可见的区域,说白了,就是你的显示屏幕。

创建一个页面要分两步走,这里,我们以创建主页面为例

 

  1. 在调用CreateSurface()函数创建一个页面之前,首先需要填充一个DDSURFACEDESC的结构,它是DirectDraw Surface Description的缩写,意思是DirectDraw的页面描述。该结构的详细资料请参MSDN。

//填充主页面信息

ddsd.dwSize = sizeof( ddsd ); //结构的大小

ddsd.dwFlags = DDSD_CAPS; //指定DDSURFACEDESC结构的ddsCaps成员为可用

ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; //指定要创建的是主页面

  • 这就象是你到银行取款,必须事先填写一张取款单,你要在上面详细描述你的姓名,你的存折序号,以及你要取的钱数等等,然后把它递给银行工作人员。
  1. 页面描述填充完毕后,把它传递给CreateSurface()函数即可。

//创建主页面对象

if ( lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL ) != DD_OK)

return FALSE;

 

CreateSurface()函数的第一个参数是被填充了页面信息的DDSURFACEDESC结构的地址,为&ddsd;第二个参数是接收主页面指针的地址,此处为&lpDDSPrimary;第三个参数现在必须为NULL,为该函数所保留。

如果函数调用成功,lpDDSPrimary将代表一个合法的主页面对象。由于在前面已经设置了该程序的工作模式为独占和全屏,所以,此时主页面所代表的实际上是你的整个显示屏幕。在主页面上所绘制的图形将立即反映到你的显示屏幕上。

 

5)输出文字

下面开始在主页面上输出文字。

//输出文字

if ( lpDDSPrimary->GetDC(&hdc) != DD_OK) return FALSE; //获得设备环境句柄

SetBkColor( hdc, RGB( 0, 0, 255 ) ); //设置背景颜色

SetTextColor( hdc, RGB( 255, 255, 0 ) ); //设置文字颜色

TextOut( hdc, 220, 200, szMsg1, lstrlen(szMsg1)); //输出文字

TextOut( hdc, 280, 240, szMsg2, lstrlen(szMsg2));

lpDDSPrimary->ReleaseDC(hdc); //释放资源

这里有一点点的小问题,这里和VC2005有区别。在注意了。TEXTOUT

通过本章的学习,读者应能掌握:

·         在VC++5.0环境中使用Win32应用程序开发环境新建一个DirectDraw工程以及添加源文件。

·         用DirectDrawCreate()函数创建DirectDraw对象,并立即调用SetCooperativeLevel()设置其控制级,注意其第一个参数为应用程序主窗口句柄。

·         只有在独占的控制级下才能调用SetDisplayMode()以改变显示器的显示模式。

·         在调用CreateSurface ()创建DirectDrawSurface对象之前,必须先填充一个DDSURFACEDESC结构以描述页面的信息。

·         页面对象的种类,只有主页面代表了显示屏幕,为可见页面。

·         用GetDC()获得主页面的HDC,然后可以使用Windows API的GDI函数进行绘图或输出文字,最后必须调用ReleaseDC()以释放资源。

·         DirectDraw接口的对象必须被及时的用Release()函数释放。

 

 

这里的代码看完了,我依然不知道为什么看不到代码所提示的现象,所以,我要看看例子程序了。我把整个例子程序的代码都复制到我的学习DirectDraw目录下面。DDraw

 

这里我看一下第一个例子。它也是在屏幕上面输出文字。

睡了一觉醒来,还是不知道哪里错了。

 

IDirectDrawSurface3::Flip

该函数完成一次换页操作。将与后台缓冲区相关联的页面内存换页成与前台缓冲区页面相关联。

HRESULT Flip(

LPDIRECTDRAWSURFACE3 lpDDSurfaceTargetOverride,

DWORD dwFlags

);

lpDDSurfaceTargetOverride -- >The default for this parameter is NULL, in which case DirectDraw cycles through the buffers in the order that they are attached to each other. 该参数缺省值是NULL,在这种情况下,DirectDraw从换页链中按照前后隶属关系依次换页。

 

DDERR_SURFACELOST

Access to the surface is refused because the surface memory is gone. Call the IDirectDrawSurface7::Restore method on this surface to restore the memory associated with it.

DDERR_WASSTILLDRAWING

The previous blit operation that is transferring information to or from this surface is incomplete.

 

 

IDirectDrawSurface7::Restore

The IDirectDrawSurface7::Restore method restores a surface that has been lost. This occurs when the surface memory associated with the DirectDrawSurface object has been freed. 恢复丢失的页面。与DirectDrawSurface对象相关联的页面内存被释放时,会导致页面丢失

 

 

经过一天的折腾,我决定把今天看到的代码自己写一遍,加深印象。

1:新建一个基于WIN32的应用程序,我这里加的不是CONSOLE应用程序,要注意拉。

 

2:

//*******************************************************************

//包含头文件

//*******************************************************************

 

#include <windows.h>

#include <ddraw.h>

#include <stdio.h>

#include <stdarg.h>  //定义成一个可变参数列表的指针

#include "resource.h" 

 

3: //*******************************************************************

//函数:WinMain()

//功能:Win32应用程序入口函数。进行初始化工作,处理消息循环

//*******************************************************************

int WINAPI WinMain(

  HINSTANCE hInstance,

  HINSTANCE hPrevInstance,

  LPWSTR lpCmdLine,

  int nShowCmd    //这里跟示例中的不一样,int PASCAL WinMain

)

{

         MSG       msg;

 

         初始化主窗口

    if (InitApp(hInstance, nCmdShow) != DD_OK)

        return FALSE;

 

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

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    return msg.wParam;

}

 

4://******************************************************************

//函数:InitApp(HINSTANCE hInstance, int nCmdShow)

//功能:创建主窗口。初始化DirectDraw环境并实现其功能。包括:创建DirectDraw对象,

//      设置显示模式,创建主页面。

//******************************************************************/

static HRESULT

InitApp(HINSTANCE hInstance, int nCmdShow)

{

    HWND                        hWnd;

    WNDCLASS                    wc;   //初始化窗口用

  

         DDSURFACEDESC2              ddsd; //The DDSURFACEDESC2 structure contains a description of a surface

    DDSCAPS2                    ddscaps;

    HRESULT                     hRet; //初始化DirectDraw环境

 

    // Set up and register window class

    wc.style = CS_HREDRAW | CS_VREDRAW;  //窗口重绘时,水平垂直重画

    wc.lpfnWndProc = WindowProc;               //WindowProc是一个函数指针,指向窗口过程函数

    wc.cbClsExtra = 0;                                        //类附加内存,默认为                   

    wc.cbWndExtra = 0;                                              //窗口附加内存,默认为        

    wc.hInstance = hInstance;

    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON));

                               //MAKEINTRESOURCE宏把资源ID标识符转换为需要的LPCTSTR类型

                                     /*HICON LoadIcon(

                                                                                      HINSTANCE hInstance,

                                                                                      LPCTSTR lpIconName

                                                                                    );

                                                                                    */

    wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));//这里的这个宏是我自己加的

    wc.hbrBackground = (HBRUSH )GetStockObject(BLACK_BRUSH);

    wc.lpszMenuName = NAME;

    wc.lpszClassName = NAME;

   

         RegisterClass(&wc);

 

    // Create a window

    hWnd = CreateWindowEx(WS_EX_TOPMOST,

                   //WS_EX_TOPMOS 的含义Specifies that a window created with this style should be placed above all

                   //non-topmost windows and should stay above them

                          NAME,

                          TITLE,

                          WS_POPUP,//窗口的类型用的是WS_POPUP,表明创建的是一个没有标题栏,没有边框的窗口;

                                                                                    //而不是常用的WS_OVERLAPPEDWINDOW

                          0,

                          0,

                          GetSystemMetrics(SM_CXSCREEN),

                          GetSystemMetrics(SM_CYSCREEN),

                          NULL,

                          NULL,

                          hInstance,

                          NULL);

    if (!hWnd)

        return FALSE;

    ShowWindow(hWnd, nCmdShow);

    UpdateWindow(hWnd);

    SetFocus(hWnd);  //功能设置键盘焦点到指定的窗口

 

    ///

    // Create the main DirectDraw object

    ///

   

         hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);

    //第二个参数是用来接受初始化成功的DirectDraw对象的地址

         //第三个参数This parameter must be set to IID_IDirectDraw7

         if (hRet != DD_OK)

        return InitFail(hWnd, hRet, "DirectDrawCreateEx FAILED");

 

    // Get exclusive mode

    hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);

    if (hRet != DD_OK)

        return InitFail(hWnd, hRet, "SetCooperativeLevel FAILED");

 

    // Set the video mode to 640x480x8

    hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0);

    if (hRet != DD_OK)

        return InitFail(hWnd, hRet, "SetDisplayMode FAILED");

 

    // Create the primary surface with 1 back buffer

    ZeroMemory(&ddsd, sizeof(ddsd));

    ddsd.dwSize = sizeof(ddsd);

    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

                                     //The dwBackBufferCount and ddsCaps member is valid.

    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |

                          DDSCAPS_COMPLEX;

                                     //DDSCAPS2 structure that contains the capabilities of the surface.

                                     //DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DSCAPS_COMPLEX; 要查看MSDN

    ddsd.dwBackBufferCount = 1;//Number of back buffers.

 

    hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);

    if (hRet != DD_OK)

        return InitFail(hWnd, hRet, "CreateSurface FAILED");

 

    // Get a pointer to the back buffer

    ZeroMemory(&ddscaps, sizeof(ddscaps));

    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

    hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);

    if (hRet != DD_OK)

        return InitFail(hWnd, hRet, "GetAttachedSurface FAILED");

 

    // Create a timer to flip the pages

    if (TIMER_ID != SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL))

        return InitFail(hWnd, hRet, "SetTimer FAILED");

 

    return DD_OK;

}

 

因为中间有很调用的函数和变量,所以要在程序中定义。

/*******************************************************************

//局部定义

//*******************************************************************

#define NAME                "DDExample1"

#define TITLE               "Direct Draw Example 1" 

 

//*******************************************************************

//全局变量

//*******************************************************************

LPDIRECTDRAW7               g_pDD = NULL;        // DirectDraw object

LPDIRECTDRAWSURFACE7        g_pDDSPrimary = NULL;// DirectDraw primary surface

LPDIRECTDRAWSURFACE7        g_pDDSBack = NULL;   // DirectDraw back surface

BOOL                        g_bActive = FALSE;   // Is application active?

 

//*******************************************************************

// 默认设置

//*******************************************************************

#define TIMER_ID            1

#define TIMER_RATE          500

 

 

函数部分

//******************************************************************/

// Name: InitFail()

// Desc: This function is called if an initialization function fails

 

//这个函数在我所学的代码里面没有。但在Win32应用程序入口函数里有代码实现了这个功能。

/*if ( !InitDDraw())

                   {

                            MessageBox(GetActiveWindow(),L"初始化DirectDraw过程中出错!",L"Error", MB_OK );

                            FreeDDraw();

                            DestroyWindow(GetActiveWindow());

                            return FALSE;

                   }*/

//******************************************************************/

HRESULT

InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...)

{

    char                        szBuff[128];

    va_list                     vl;

 

    va_start(vl, szError); //va在这里是variable-argument(可变参数)的意思.

    vsprintf(szBuff, szError, vl);

   

         ReleaseAllObjects();

    MessageBox(hWnd, szBuff, TITLE, MB_OK);

    DestroyWindow(hWnd);

   

         va_end(vl);

   

         return hRet;

}

 

//这里的关于可变参数的问题我没有深入。好烦的。

 

 

//******************************************************************/

// Name: ReleaseAllObjects()

// Desc: Finished with all objects we use; release them

// 这里的代码跟我所学的代码差不多,只是符号有所变化。

//******************************************************************/

static void

ReleaseAllObjects(void)

{

    if (g_pDD != NULL) //g_pDD is DirectDraw object

    {

        if (g_pDDSPrimary != NULL) //g_pDDSPrimary is DirectDraw primary surface

        {

            g_pDDSPrimary->Release();

            g_pDDSPrimary = NULL;

        }

        g_pDD->Release();

        g_pDD = NULL;

    }

}

 

 

5:这里我就不接着写了,写几个关键的地方,

   第一个就是函数的顺序的问题。

         第二个要在Project->Configuration Properties->General->Character Set,选择“Use Unicode Character Set”就是使用Uncode字符集,选择” Use Multi-Byte Character Set”就是多字节字符集。

第三个Project->Configuration Properties->linker->additional dependenices ->dxguid.lib ddraw.lib 加入这两个库

第四个,注意修改int WINAPI WinMain(

HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine, //这个参数的类型要改一下

int nCmdShow )  //这个参数的名字要改一下

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值