Microsoft DirectX 8.0

Debugging with DirectShow

This article provides some tips for debugging Microsoft® DirectShow® applications and filters.

This article contains the following sections:

See also: Simulating Graph Building with GraphEdit

Assertion Checking

Use assertion checking liberally. Assertions can verify assumptions that you make in your code about preconditions and postconditions. DirectShow provides several assertion macros. For more information, see Assert and Breakpoint Macros.

For example, a pin class might contain a private method that assumes the pin is connected. You can test this assumption with an assertion, as follows:

ASSERT(IsConnected());  // Pin must be connected.

Object Names

In debug builds, there is a global list of objects that derive from the CBaseObject class. As objects are created, they are added to the list. When they are destroyed, they are removed from the list. To display a list of those objects, call the DbgDumpObjectRegister function.

The constructor method for the CBaseObject base class—and most classes derived from it—includes a parameter for the name of the object. Give your objects unique names to identify them. If you use the NAME macro when you declare the name, storage for the name is only allocated in debug builds. In retail builds, the name becomes NULL.

Debug Logging

The DbgLog function displays debugging messages as your program executes. Use this function to trace the execution of your application or filter. You can log return codes, the values of variables, and any other relevant information.

Every debug message has a type, such as LOG_TRACE or LOG_ERROR, and a debug level, which indicates the importance of the message. Messages with lower debug levels are more important than those with higher levels.

In the following example, a hypothetical filter disconnects a pin from an array of pins. If the disconnect attempt succeeds, the filter displays a LOG_TRACE message. If the attempt fails, it displays a LOG_ERROR message:

hr = m_PinArray[iPin]->Disconnect();
if (FAILED(hr))
{
    DbgLog((LOG_ERROR, 1, TEXT("Could not disconnect pin %d. HRESULT = %#x", iPin, hr));
 
   // Error handling code (not shown).
}
DbgLog((LOG_TRACE, 3, TEXT("Disconnected pin %d"), iPin));

When you are debugging, you can set the debug level for each message type. Also, each module (DLL or executable) maintains its own debugging levels. If you are testing a filter, raise the debug levels for the DLL that contains the filter. For more information, see Debug Output Functions.

Critical Sections

To make deadlocks easier to track, include assertions that determine whether the calling code owns a given critical section. The CritCheckIn and CritCheckOut functions indicate whether the calling thread owns a critical section. Typically, you would call these functions from inside an assert macro. For more information, see CCritSec Debug Functions.

You can also use the DbgLockTrace function to trace when critical sections are held or released.

Pointer Validation

Consider validating pointers. For example, the ValidateReadPtr macro checks whether a specified pointer points to readable memory. Currently, the DirectShow pointer validation macros use Microsoft® Win32® pointer validation functions, such as IsBadReadPtr. On some systems, these functions swap in every page in the specified range, which can greatly reduce performance. For more information, see Pointer Validation Macros.