父,子对象的活动时间

  你在DirectDraw中使用的对象如:DirectDraw对象、平面、调色板、剪切, 在内存中创建的时候,就象应用程序,就有了活动时间。 从对象创建并放入内存一刻一直到被释放随后被从内存中删除的这段时间就是对象的活动时间。 所有的DirectX对象完全都遵照构件对象模型(COM)的允许及支配, 也就是一个对象必须以有多少其他对象需要他的服务来决定。这个数字, 也就是前面提到过的关联值(译者按:关于关联值参见1.2文档), 并决定对象的活动时间。COM也允许通过IUnknown::AddRef及IUnknown::Release 宏来改变管理其关联值(译者按:关于这两个宏同样参见1.2文档); 确定你在使用这些宏时与COM规则相一致。

  不会只有你使用IUnknown宏来管理DirectDraw对象关联值,对象也在内部使用关联值。 当你使用IDirectDraw4界面(与IDirectDraw2及IDirectDraw相反)创建一个"子"对象例如平面, 子对象在父DirectDraw对象上使用IUnknown::AddRef宏来增加父对象的关联值。 当你的应用程序不再需要一个对象,调用Release宏来减少它的关联值。当关联值为零时, 对象便从内存中被删除。当一个子对象的关联值为零时,它调用父对象的IUnknown::Release 宏来指出已经没有对象需要父对象的服务。

  一些暗中存在的对象,如:在调用一次IDirectDraw4::CreatSurface后创建的交换链 (译者按:Flipping Chain暂时译为交换链, 云风:切换链是不是更贴切点?) (译者按:Flip:屏后缓冲Back-Buffer与前景缓冲Front-Buffer的联合地址的交换过程, 可以有效的将屏后缓冲的图象交换到前景缓冲,然后显示图象。Flipping Chain:一组互相连接的平面,能被页交换) 的屏后缓冲平面,会在它们的父对象DirectDrawSurface对象释放后被自动解除。 还有,你只能在创建程序窗口后再可以在线程中释放DirectDraw对象。对于单线程程序, 这个限制明显无法适用,因为仅仅只有一个线程。如果你的程序使用附带的DirectDrawClipper 对象创建一个主两个平面的交换链(由一次调用CreateSurface创建),要安全释放这些对象代码应为:

// For this example, the g_lpDDraw, g_lpDDSurface, and
// g_lpDDClip are valid pointers to objects.
// 对于这个例子,g_lpDDraw,g_lpDDSurface及g_lpDDclip都是
// 有效的对象指针。
void ReleaseDDrawObjects(void)
{
    // If the DirectDraw object pointer is valid,
    // it should be safe to release it and the objects it owns.
    // 如果DirectDraw对象的指针有效,
    // 便可以安全得释放它及对象自己。
    if(g_lpDDraw)
    {
        // Release the DirectDraw object. (This call wouldn't
        // be safe if the children were created through IDirectDraw2 
        // or IDirectDraw. See the following note for
        // more information)
        // 释放DirectDraw对象。(这个调用在子对象是由IDirectDraw2
        // 或IDirectDraw创建时并不安全,详见后面的注意)
        g_lpDDraw->Release(), g_lpDDraw = NULL;
 
        // Now, release the clipper that is attached to the surfaces.
        // 现在,释放附带于平面的DirectDrawClipper对象
        if(g_lpDDClip)
            g_lpDDClip->Release(), g_lpDDClip = NULL;
 
        // Now, release the primary flipping chain. Note
        // that this is only valid because the flipping 
        // chain surfaces were created with a single 
        // CreateSurface call. If they were explicitly
        // created and attached, then they must also be
        // explicitly released.
        // 现在,释放主交换链。注意:这只对一次调用CreateSurface
        // 创建的交换链有效。如果它们是被直接创建的或是附带的,
    // 那么它们必须也被直接释放。
        if(g_lpDDSurface)
            g_lpDDSurface->Release(), g_lpDDSurface = NULL;
    }
}
 

注意:

  老版本的DirectDraw界面(确切的说就是IDirectDraw2及IDirectDraw) 做法与现在的界面不同。当使用这些界面,DirectDraw会在父对象被释放后自动释放所有的子对象。 从而导致,如果你使用这些老界面,你释放对象是有危险的。在这种情况下, 你需要在释放父对象前释放所有子对象(或不全释放它们,依靠父对象来为你清除)。 因为DirectDraw对象释放子对象,如果你先释放父对象, 你就有可能在父对象释放子对象时遭遇一个试图重复引用一个指针的内存错误。

  一些老的程序在不需要子对象时依靠其自动释放子对象而疏忽了适当释放它们。 可能当时不会造成一些负面影响,不管怎样,这样使用IDirectDraw4界面时会导致内存溢出。

多个DirectDraw对象一个过程

  DirectDraw允许一个过程多次调用DirectDrawCreate函数。 一个独一无二及独立的界面到一个独一无二及独立的DirectDraw对象会在每次调用后返回。 每个DirectDraw对象都可以被使用;每个对象间都无联系。每个对象都与单独过程创建的对象毫无区别。

  每个DirectDraw对象都相互独立及独立的DirectDrawSurface,DirectDrawPalette及 DirectDrawClipper对象,它们不能用于其他的DirectDraw对象,因为在父对象被销毁后子对象会被自动释放。 如果用于其他的DirectDraw对象,它们就会在它们的父对象被销毁失去作用,使剩下的DirectDraw对象不起作用。

  除了DirectDrawClipper对象是使用DirectDrawCreateClipper函数创建的。 这些对象与其他特殊的DirectDraw对象可以用于一个或多个DirectDraw对象。

用CoCreateInstance创建DirectDraw对象

  你可以用CoCreateInstance函数及IDirectDraw4::Initialize宏来代替 DirectDrawCreate函数来创建DirectDraw对象。以下过程描述如何创建DirectDraw对象:

  1. 程序开始时调用CoInitialize指定NULL初始化COM。
    if (FAILED(CoInitialize(NULL)))
        return FALSE;
    
  2. 使用CoCreateInstance及IDirectDraw4::Initialize宏创建DirectDraw对象
    ddrval = CoCreateInstance(&CLSID_DirectDraw,
        NULL, CLSCTX_ALL, &IID_IDirectDraw4, &lpdd);
    if(!FAILED(ddrval))
        ddrval = IDirectDraw4_Initialize(lpdd, NULL);
    

      调用CoCreateInstance,第一个参数,CLSID_DirectDraw,是DirectDraw驱动对象类的类标识符, IID_IDirectDraw4参数标识何种的DirectDraw对象将被创建。如果调用成功,函数返回一个未初始化的对象。

  3.   在你调用DirectDraw对象前,你必须调用IDirectDraw4::Initialize。 这个宏传递驱动程序的GUID(全局单一描述符Globally unique identifier)参数, 是DirectDrawCreate函数要使用的(这里为NULL)。在DirectDraw对象初始化后, 你就可以使用或释放它,就象用DirectDrawCreate函数创建的对象一样。 如果你在使用与DirectDraw对象联合的宏之前不调用初始化宏, 就会产生一个DDERR_NOTINITIALIZED错误。

  在关闭应用程序前,使用CoUninitialize函数关闭COM库。

    CoUninitialize();

上篇|返回|下篇

Lucker 1999.3.5
E-Mail: fred_cai@kali.com.cn

下一篇开始就是DirectDraw中的平面,就要开始深入DirectDraw。 和以前一样希望大家踊跃提出翻译中错误的地方。在此感谢。


云风工作室 制作