All objects you'll use in DirectDraw programming—the DirectDraw object, surfaces, palettes, clippers, and such—only exist in memory for as long as another object, such as an application, needs them. The time that passes from the moment when an object is created and placed in memory to when it is released and subsequently removed from memory is known as the object's lifetime. The Component Object Model (COM) followed by all DirectX components dictates that an object must keep track of how many other objects require its services. This number, known as a reference count, determines the object's lifetime. COM also dictates that an object expose the IUnknown::AddRef and IUnknown::Release methods to enable applications to explicitly manage its reference count; make sure you use these methods in accordance to COM rules.
You aren't the only one who is using the IUnknown methods to manage reference counts for objects—DirectDraw objects use them internally, too. When you use the IDirectDraw4 interface (in contrast to IDirectDraw2 or IDirectDraw) to create a "child" object like a surface, the child uses the IUnknown::AddRef method of the "parent" DirectDraw object to increment the parent's reference count.
When your application no longer needs an object, call the Release method to decrement its reference count. When the count reaches zero, the object is removed from memory. When a child object's reference count reaches zero, it calls the parent's IUnknown::Release method to indicate that there is one less object who will be needing the parent's services.
Implicitly allocated objects, such as the back-buffer surfaces in a flipping chain that you create with a single IDirectDraw4::CreateSurface call, are automatically deallocated when their parent DirectDrawSurface object is released. Also, you can only release a DirectDraw object from the thread that created the application window. For single-threaded applications, this restriction obviously doesn't apply, as there is only one thread. If your application created a primary flipping chain of two surfaces (created by a single CreateSurface call) that used an attached DirectDrawClipper object, the code to release these objects safely might look like:
// For this example, the g_lpDDraw, g_lpDDSurface, and
// g_lpDDClip are valid pointers to objects.
void ReleaseDDrawObjects(void)
{
// If the DirectDraw object pointer is valid,
// it should be safe to release it and the objects it owns.
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)
g_lpDDraw->Release(), g_lpDDraw = NULL;
// Now, release the clipper that is attached to the surfaces.
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.
if(g_lpDDSurface)
g_lpDDSurface->Release(), g_lpDDSurface = NULL;
}
}
Note Earlier versions of the DirectDraw interface (IDirectDraw2 and IDirectDraw, to be exact) behave differently than the most recent interface. When using these early interfaces, DirectDraw automatically releases all child objects when the parent itself is released. As a result, if you use these older interfaces, the order in which you release objects is critical. In this case, you should release the children of a DirectDraw object before releasing the DirectDraw object itself (or not release them at all, counting on the parent to do cleanup for you). Because the DirectDraw object releases the child objects, if you release the parent before the children, you are very likely to incur a memory fault for attempting to dereference a pointer that was invalidated when the parent object released its children.
Some older applications relied on the automatic release of child objects and neglected to properly release some objects when no longer needed. At the time, this practice didn't cause any negative side effects, however doing so when using the IDirectDraw4 interface might result in memory leaks.