JavaScript EditorFree JavaScript Editor     Ajax Editor 



Main Page
  Previous Section Next Section

Creating a DirectDraw Object

To create a DirectDraw 1.0 object with C++, all you need to do is call DirectDrawCreate(), shown here:

HRESULT WINAPI DirectDrawCreate(GUID FAR *lpGUID,   // guid of object
                 LPDIRECTDRAW FAR *lplpDD, // receives interface
                 IUnknown     FAR *pUnkOuter ); // com stuff

LpGUID— This is the GUID (Globally Unique Identifier) of the display driver that you want to use. In most cases, you'll simply send NULL to represent the default hardware.

lplpDD— This is a pointer to a pointer that receives the IDirectDraw interface pointer if the call is successful. Note that the function returns a IDirectDraw interface, not a IDirectDraw7 interface!

pUnkOuter— Advanced feature; always send NULL.

Here's how you would use the function to create a default DirectDraw object based on the IDirectDraw interface:

LPDIRECTDRAW lpdd = NULL; // storage for IDirectDraw

// create the DirectDraw object
DirectDrawCreate(NULL, &lpdd, NULL);

If the function is successful, lpdd will be a valid IDirectDraw 1.0 object interface. However, you still would like that latest interface, IDirectDraw7. But before you learn how to do that—what about error handling?

Error Handling with DirectDraw

Error handling in DirectX is very clean. There are a number of macros that can test the results of any function for general success or failure. The Microsoft-endorsed way of testing for errors with DirectX functions is to use these two macros:

FAILED()— Tests for failure.

SUCCEEDED()— Tests for success.

Based on this new information, you could do something smart by adding the following error handling code:

if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL)))
   {
   // error
   } // end if

Or similarly, you could test for success:

if (SUCCEEDED(DirectDrawCreate(NULL, &lpdd, NULL)))
   {
   // move onto next step
   } // end if
else
   {
   // error
   } // end else

I usually use the FAILED() macro because I don't like having two different logic paths, but whatever lights your fusion reactor… The only problem with the macros is that they don't tell you much; they are more to detect a general problem. If you want to know the exact problem, you can always take a look at the return code for the function. In this case, Table 6.1 lists the possible return codes for DirectX version 6.0 DirectDrawCreate().

Table 6.1. Return Codes for DirectDrawCreate()
Return Code Description
DD_OK Total Success.
DDERR_DIRECTDRAWALREADYCREATED DirectDraw object has already been created.
DDERR_GENERIC DirectDraw has no idea what's wrong.
DDERR_INVALIDDIRECTDRAWGUID The device GUID is unknown.
DDERR_INVALIDPARAMS Something is wrong with the parameters you sent.
DDERR_NODIRECTDRAWHW There isn't any hardware.
DDERR_OUTOFMEMORY Take a wild guess?

The only problem with using the constants along with conditional logic is that Microsoft doesn't guarantee that they won't completely change all the error codes. However, I think that you'll be pretty safe with

if (DirectDrawCreate(...)!=DD_OK)
   {
   // error
   } // end if

in all cases. Moreover, DD_OK is defined for all DirectDraw functions, so you can use it safely without worrying.

Getting an Interface Lift

As I said, you can use the basic IDirectDraw interface stored in lpdd from the call to DirectDrawCreate(). Or you can upgrade it to the latest version (whatever it may be) by querying for a new interface via the IUnknown interface method QueryInterface(), which is part of every DirectDraw interface implementation. The latest DirectDraw interface as of DirectX version 7.0 is IDirectDraw7, so here's how you retrieve the interface pointer:

LPDIRECTDRAW lpdd  = NULL; // standard DirectDraw 1.0
LPDIRECTDRAW lpdd7 = NULL; // DirectDraw 7.0 interface 7

// first create base IDirectDraw interface
if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL)))
   {
   // error
   } // end if

// now query for IDirectDraw7
if (FAILED(lpdd->QueryInterface(IID_IDirectDraw7,
                               (LPVOID *)&lpdd7)))
   {
   // error
   } // end if

Now, here are the important things to pay attention to:

  • The way that QueryInterface() is called.

  • The constant used to request the IDirectDraw7 interface, which is IID_IDirectDraw7.

In general, all calls from an interface are in the form

interface_pointer->method(parms...);

And all interface identifiers are in the form

IID_IDirectCD

Here, C refers to the component: Draw for DirectDraw, Sound for DirectSound, Input for DirectInput, and so on. D is a number, from 2 to n, indicating the interface you desire. In addition, you can find all these constants within the DDRAW.H file.

Moving on with this example, you now have a bit of a dilemma—you have both a IDirectDraw interface and a IDirectDraw7 interface. What to do? Simply blow the old interface away since you don't need it, like this:

lpdd->Release();
lpdd = NULL; // set to NULL for safety

And from this point on, do all method calls using the new interface IDirectDraw7.

WARNING

Along with the new functionality of IDirectDraw7 comes a little housekeeping and responsibility. The problem is that not only is the IDirectDraw7 interface more sophisticated and advanced, but in many cases it needs and returns new data structures rather than the base structures defined for DirectX 1.0. The only way to be sure about these anomalies is to take a look at the DirectX SDK documentation and verify the version of the data structure that any specific function needs and/or returns. However, this is just a warning in general. I'll show you the correct structures for all the examples that you work through in this book—because I'm that kind of guy! By the way, my birthday is on June 14th.


In addition to using the QueryInterface() function from the initial IDirectDraw interface pointer (lpdd), there is a more direct "COM way" of getting the IDirectDraw7 interface directly. Under COM, you can retrieve an interface pointer to any interface as long as you have the Interface ID, or IID, that represents the interface that you desire. In most cases, I personally prefer not to use low-level COM functions because I already have enough drama in my life. Nevertheless, when you get to DirectMusic there will be no way around using low-level COM stuff, so this is a good place to at least introduce the process to you. Here's how you would directly obtain an IDirectDraw7 interface:

// first initialize COM, this will load the COM libraries
// if they aren't already loaded
if (FAILED(CoInitialize(NULL)))
   {
   // error
   } // end if

// Create the DirectDraw object by using the
// CoCreateInstance() function
if (FAILED(CoCreateInstance(&CLSID_DirectDraw,
                             NULL,
                             CLSCTX_ALL,
                             &IID_IDirectDraw7,
                             &lpdd7)))
   {
   // error
   } // end if


// now before using the DirectDraw object, it must
// be initialized using the initialize method

if (FAILED(IDirectDraw7_Initialize(lpdd7, NULL)))
   {
   // error
   } // end if
// now that we're done with COM, uninitialize it
CoUninitialize();

The preceding code is the Microsoft-recommended way to create a DirectDraw object. However, the technique does cheat a bit and use one macro:

IDirectDraw7_Initialize(lpdd7, NULL);

You can get rid of this and be totally COM by replacing it with

lpdd7->Initialize(NULL);

where the NULL in both calls is the video device, which in this case is the default driver. (That's why it's been left NULL.) In any case, it's not hard to see how the macro expands out into the code in the preceding line. Just makes life easier, I guess? Now, for the good news, Microsoft has created a function call that will actually create an IDirectDraw7 interface without the intermediate steps. Usually, this was not the case, but in DirectX version 7.0 they created a new function called DirectDrawCreateEx() which I mentioned before in the last chapter. Its prototype looks like this

'HRESULT WINAPI DirectDrawCreateEx(

  GUID FAR *lpGUID,  // the GUID of the driver, NULL for active display

  LPVOID *lplpDD,    // receiver of the interface

  REFIID iid,       // the interface ID of the interface you are requesting

  IUnknown FAR *pUnkOuter  // advanced COM, NULL

);

It's very similar to the simpler DirectDrawCreate(), but takes more parameters and allows you to create any DirectDraw interface. In any case, the call to create the IDirectDraw7 interaface would look like this:

LPDIRECTDRAW7 lpdd;  // version 7.0

// create version 7.0 DirectDraw object interface
DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL);

The only tricky part is the casting of the interface pointer, note the (void **) and you must send the requested interface in the parameter iid. Other than that, it's pretty simple and just works!

Let's take a minute to reiterate everything here. Ok, we need an IDirectDraw7 interface if we want to work with the latest version of DirectDraw which is version 7.0 (since in version 8.0 Microsoft removed DirectDraw). We can use the basic DirectDrawCreate() function and get an IDirectDraw 1.0 interface, and then from there use QueryInterface() to get IDirectDraw7. On the other hand, we can use low level COM and get IDirectDraw7 directly, or we can use the function DirectDrawCreateEx() that is available since the release of DirectX 7.0 to create the interface directly. Nice, huh? DirectX is starting to sound like X Windows, about 5,000 ways to do everything <BG>.

Now that you know how to create a DirectDraw object and obtain the latest interface, let's move on to the next step in the sequence of getting DirectDraw working, which is setting the cooperation level.

      Previous Section Next Section
    



    JavaScript EditorAjax Editor     JavaScript Editor