The Basics

DirectX is loosley based on Microsofts Component Object Model (COM for short) the technology behind ActiveX controls. COM deals heavilly in interfaces where an interface is (in C++ terms) a pointer to a table of function pointers - usually defined in a header file as a class containing pure virtual functions.

Interfaces have names. The main DirectDraw interface is called IDirectDraw. Calling function son this interface is how you "do" DirectX. You get a IDirectDraw interface pointer by calling DirectDrawCreate as shown in the following code sample.

The IDirectDraw interface was introduced with DirectX 1. Two more DirectDraw interfaces are available which are extensions of the IDirectDraw interface - they add some new functions but change none of the older functions. QueryInterface is a method in the IUnknown interface that all COM interfaces inherit from. As IDirectDraw is the first interface obtained it is the interface most often "queried" for the other interfaces. Any interface however can be asked for any other interface the obejct supports.

This code sample demonstrates how to get the IDirectDraw interface, and how you might query for IDirectDraw2 and IDirectDraw4 interfaces. The error handling is completely poked and obviously not suitable for a real application.

IDirectDraw* pDDraw;
HRESULT hr;
hr = DirectDrawCreate(NULL,&iDirectDraw,NULL);
if(!SUCCEEDED(hr))
  return hr;

IDirectDraw2* pDDraw2;
hr=pDDraw->QueryInterface(IID_IDirectDraw2,(void**)&pDDraw2);
if(!pDDraw2)
  return hr;

IDirectDraw4* pDDraw4;
hr=pDDraw->QueryInterface(IID_DirectDraw4,(void**)&pDDraw4);
if(!pDDraw4)
  return hr;

DirectX 7 has introduced a new interface: IDirectDraw7 but you cannot query IDirectDraw for it (or, having an IDirectDraw7 interface qury for any of the earlier interfaces. The DirectX team's COM application is quite frankly shocking, but is slowley getting better.

There are now two ways to obtain an IDirectDraw7 interface. DirectX 7 installs itself as a "proper" ActiveX control - you can obtain a DirectX7 (and higher) object by calling the COM function CoCreateInstance. The "traditional" DirectDrawCrate has been superseeded by DirectDrawCreateEx.

The next code sample demonstrates the two ways of creating a DirectX 7 DirectDraw object:

IDirectDraw7* pDD_A;
HRESULT hr;
hr = CoCreateInstance(CLSID_DirectDraw,NULL,CLCTX_ALL,IID_IDirectDraw7,(void**)&pDD_A);
pDD_A->Initialize(NULL);


IDirectDraw7* pDD_B;
hr = DirectDrawCreateEx(NULL,(void**)pDD_A,IID_IDirectDraw7,NULL);

FullScreen Applications (the importance of not ignoring GDI).

This code snippet shows the code necessary to enter (and leave) fullscreen mode.

iDirectDraw->SetCooperativeLevel(hwnd,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
iDirectDraw->SetDisplayMode(640,480,16);

What do these functions actually do?

SetCooperativeLevel is used to indicate to the system how your application wishes to co-exist with other applications.

DDSCL_EXCLUSIVE
This flag enables DirectX's "hiding" logic. Whenever your DirectX application loses focus (the user alt-tabs away) DirectX will hide the application window and, if necessary, change resolution. When the DirectX application regains focus DirectX will restore the applications resolution, and resize and position the application window to fit the display exactly.
DDSCL_FULLSCREEN
This flag enables DirectX's sizing logic alluded to in the DDSCL_EXCLUSIVE dox above. On a number of events - notably this call, as well as whenever the resolution changes the application window is resized to fit the display exactly.

These two flags *must* be used together, and also *must* be used before calling SetDisplayMode to change the resolution. I lie of course; calling SetDisplayMode without setting the cooperative level will work - kindof. I certainly don't recommend making an application that relies on this behaviour.

Finally to set the desired resolution you call SetDisplayMode(). This will change to the set resolution, and, if DDSCL_FULLSCREEN was set, ensures that the application window is maximized.

At this point notice a remarkable thing. Dispite requests for fullscreen exclusive access GDI (and the window manager) is still working. You can now manually move your application window and see that behind it is the window desktop, and any windows that were visible on the desktop are there. Clicking on them will however transfer activation from you app, so DirectX will (assuming you havn't tricked it by not setting the co-operative level) restore the desktop resolution and hide the "exclusive mode" application.

Well, if you are porting a GDI game to DirectX to make use of the FullScreen feature here you can stop. You have a working window that you can paint on using GDI. That window also happens to be "fullscreen".

This brings up another important point. Setting up the frame window styles for a "proper" fullscreen exclusive mode application.

WS_EX_TOPMOST
WS_EX_TOPMOST is a must. Even though you have that supposed full screen exclusive mode access to the display other windows continue to be drawn according to GDI & the window managers rules. This means if, say, taksmanager, or some other "topmost" window (such as ICQ) is visible in the top left of the display these windows will be visible over your application window in fullscreen mode. WS_EX_TOPMOST will ensure that your window is "topmost of the topmost" - avoiding this problem.
WS_POPUP
Allowing your user to drag your "DirectX" fullscreen so users can see the desktop below is unprofessional. WS_POPUP avoids the whole "drag" thing by ensuring that the app window has no caption or sizable border styles (that frankly look ugly in fullscreen apps anyway).