David Joffe's Guide to Programming Games with DirectX
Chapter 3: A simple DirectDraw sample
3.1 Setting up DirectX under Visual C/C++ I most likely won't be doing DirectX development under Watcom or Borland C/C++ or Delphi or VisualBASIC etc; so if you want such info included, please send as much info as you can on generally getting DirectX programs to compile in these environments + troubleshooting etc.
Firstly, the directories must be set up so that Visual C/C++ can find the DirectX include files and libraries.
Access the Tools/Options/Directories tabbed dialog.
Select "library directories" from the drop-down list, and add the directory of the DX SDK libraries, e.g. "d:\dxsdk\sdk\lib"
Select "include directories" from the drop-down list, and add the directory of the DX SDK header files, e.g. "d:\dxsdk\sdk\inc".
If you are going to be using some of the DX utility headers used in the samples, then also add the samples\misc directory, e.g. "d:\dxsdk\sdk\samples\misc".
Note: In Visual C/C++ 4.2, the header file directory for the DirectX SDK must be located *before* the default VC++ development include directories, so that the compiler searches the DXSDK directories first. As far as I can tell, the reason for this is that with VC++ 4.2 some of the DirectX was included, but those header files seem to be out of date or something because they don't work.
To use DirectDraw you must tell it which library file the DirectDraw routines are in. Ditto for Direct3D. Go to Build/Settings/Link and in the Object/Library modules box add ddraw.lib to use DirectDraw, and d3drm.lib if you want to use Direct3D Retained mode. Seperate these with spaces.
Firstly, heres a screenshot of the small simple sample application we're putting together here.
The general routine for starting a DirectDraw application is the following:
3.3 Setting up global variables: Globals.h and Globals.cpp We are going to need a number of global variables for our DirectDraw application. Firstly, we need a variable for accessing the DirectDraw object. Also, we'll need a boolean variable to track whether or not we are in full-screen mode, called bFullScreen. Then we need two DirectDrawSurface variables for the primary surface and the back surface which form our double-buffered surface-flipping structure. For windowed mode, we'll need a clipper object to attach to the primary surface to prevent DirectDraw from drawing outside of the window's edges. If using a 256 color mode, we'll probably want a structure to store the palette we are going to use. Then, we need an HWND object to let the clipper know which window's boundaries it should clip to. Finally, we'll need a boolean variable to start and stop animation of the DirectDraw application, once it is initialized. Create a global variable for purposes of accessing the DirectDraw object, and a boolean variable to track whether or not we are in full-screen mode.
These global variables, along with the global functions, I place in a seperate file called Globals.cpp which I add to my project in Visual C/C++. They could all have been members of a class, but I have chosen to make them global for easier access across all modules, to conceptually seperate the DX stuff from the rest of the program code, and to make it simpler to use these functions in non-MFC applications.
I also make a function to initialize all of these variables:
Here is the general layout of my Globals.h and Globals.cpp files:
Globals.h Globals.cpp 3.4 Initializing the DirectDraw system Now we need a routine to initialize the directdraw system. The DirectDraw system must be initialized every time you switch between full-screen and windowed mode (I think :) - gimme a bit of time). The DirectDrawCreate function call is used to create a DirectDraw object.
The function SetCooperativeLevel is used to tell the system whether or not we want to use full-screen mode or windowed. In full-screen mode, we have to get exclusive access to the DirectDraw device, and then set the display mode. For windowed mode, we set the cooperative level to normal.
OK ... now that we've got that bit of initialization out of the way, we need to create a flipping structure. No, I'm not cursing the structure .. "flipping" as in screen page-flipping :).
Anyway, we need to create one main surface that everyone will see, and a "back" surface. All drawing is done to the back surface. When we are finished drawing we need to make what we've drawn visible. In full-screen mode, we just need to call a routine called Flip, which will turn the current back surface into the primary surface and vice versa. In windowed mode, we don't actually flip the surfaces - we copy the contents of the back buffer onto the primary buffer, which is what's inside the window. In other words, we "blit" the back surface onto the primary surface.
Anyway, here is the bit of code to create the surfaces. Right now the code is ignoring full-screen mode and only catering for windowed mode, but that'll change. Also, if there are errors in this code, consider them "exercises" ... :). Naah, just kidding. If there are errors, mail me.
Now that we've created the surfaces, we need to create a clipper (if we're running in windowed mode), and attach the clipper to the primary surface. This prevents DirectDraw from drawing outside the windows client area.
Now that we have all these initialization routines, we need to actually call them, so the question is, where to call them? In an MFC application, a logical place to do this is in the application's InitInstance routine.
As if all this initialization wasn't enough, we also have to make sure our DirectDraw surfaces are not getting "lost". The memory associated with DirectDraw surfaces can be released under certain circumstances, because it has to share resources with the Windows GDI. So each time we render, we first have to check if our surfaces have been lost and Restore them if they have. This is accomplished with the IsLost function.
Now that we've got most of the general initialization out of the way, we need to set up a rendering loop. This is basically the main loop of the game, the so-called HeartBeat function. So we're going to call it just that.
The HeartBeat function gets called during your applications idle-time processing; so we need to override the application's OnIdle function. Use ClassWizard or the toolbar wizard thingy to create a handler for idle-time processing for your main application class. Here I am assuming you know a bit about MFC. Sorry about that; that'll probably change though with time as my knowledge improves and as I have more time to work on this.
Note that your applications OnIdle handler gets called even when your program does not have the current focus, and we'd rather not have your application do anything unless it has the current focus. Trust me on this one :). This is what we use bAnimating for; we set it to FALSE when we receive the WM_ACTIVATE(APP?) message with a parameter of FALSE. We set this variable to TRUE just after we've set up DirectDraw and the surfaces etc., and we are ready to begin.
Now let's look at the heartbeat function. At the moment mine just draws a silly block in the top left of the window that changes color each frame.
Now let's look at the function that performs the surface flipping. This time I *do* take full-screen mode into account ... I'm inconsistent, eh? :-).
3.13 Tracing DirectDraw errors Here is a pretty useful debugging function for DirectX apps, called TraceErrorDD:
Coming soon.
LPDIRECTDRAW pDD; // DirectDraw object
LPDIRECTDRAWSURFACE pDDSPrimary; // DirectDraw primary surface
LPDIRECTDRAWSURFACE pDDSBack; // DirectDraw back surface
LPDIRECTDRAWPALETTE pDDPal; // Palette (coming sometime soonish)
LPDIRECTDRAWCLIPPER pClipper; // Clipper for windowed mode
HWND ddWnd; // Handle of window
BOOL bFullScreen; // are we in fullscreen mode?
BOOL bAnimating; // are we animating?
void InitDirectXGlobals()
{
pDD = NULL;
pDDSPrimary = NULL;
pDDSBack = NULL;
pDDPal = NULL;
pClipper = NULL;
bFullScreen = FALSE;
bAnimating = FALSE;
}
#ifndef _GLOBALS_H_
#define _GLOBALS_H_
include <d3drm.h>
extern LPDIRECTDRAW pDD;
...
extern void InitDirectXGlobals();
...
#endif
#include "stdafx.h"
#include <ddraw.h>
#include <d3drm.h>
#include "Globals.h"
LPDIRECTDRAW pDD;
...
void InitDirectXGlobals()
{
pDD = NULL;
...
}
BOOL InitDDraw()
{
HRESULT hr;
// Create the DirectDraw object
// The first NULL means use the active display driver
// The last parameter must be NULL
hr = DirectDrawCreate(NULL, &pDD, NULL);
if (FAILED(hr)) {
TRACE("Unable to create DDraw object\n");
return FALSE;
}
// The DirectDraw object initialized successfully
return TRUE;
}
BOOL SetMode() {
HRESULT hr;
if (bFullScreen) {
// Set the "cooperative level" so we can use full-screen mode
hr = pDD->SetCooperativeLevel(AfxGetMainWnd()->GetSafeHwnd(),
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES);
if (FAILED(hr)) {
pDD->Release();
return FALSE;
}
// Set 640x480x256 full-screen mode
hr = pDD->SetDisplayMode(640, 480, 8);
if (FAILED(hr)) {
TRACE("Error setting display mode: %d\n", int(LOWORD(hr)));
pDD->Release();
return FALSE;
}
} else {
// Set DDSCL_NORMAL to use windowed mode
hr = pDD->SetCooperativeLevel(AfxGetMainWnd()->GetSafeHwnd(),
DDSCL_NORMAL);
}
// Success
return TRUE;
}
UINT CreatePrimarySurface()
{
DDSURFACEDESC ddsd; // A structure to describe the surface we want
HRESULT hr; // Holds return values for function calls
// Screw the full-screen mode (for now)
// This clears all fields of the DDSURFACEDESC structure to 0
memset(&ddsd, 0, sizeof(ddsd));
// The first parameter of the structure must contain the
// size of the structure.
ddsd.dwSize = sizeof(ddsd);
// The dwFlags paramater tell DirectDraw which DDSURFACEDESC
// fields will contain valid values
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
// Create the primary surface
hr = pDD->CreateSurface(&ddsd, &pDDSPrimary, NULL);
if (FAILED(hr))
{
TRACE("Error: pDD->CreateSurface (primary)\n");
TraceErrorDD(hr);
pDD->Release();
pDD = NULL;
return 1;
}
// Now to create the back buffer
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
// Make our off-screen surface 320x240
ddsd.dwWidth = 320;
ddsd.dwHeight = 240;
// Ignore this: I'm trying stuff still
/*memset(&ddsd.ddpfPixelFormat, 0, sizeof(ddsd.ddpfPixelFormat));
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddsd.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8;
// ddsd.ddpfPixelFormat.dwRGBBitCount = 8;*/
// Create an offscreen surface
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
hr = pDD->CreateSurface(&ddsd, &pDDSBack, NULL);
if (FAILED(hr)) {
TRACE("Error: CreateSurface (back)\n");
TraceErrorDD(hr);
return 2;
}
// success
return 0;
}
UINT CreateClipper()
{
HRESULT hr;
// Create the clipper using the DirectDraw object
hr = pDD->CreateClipper(0, &pClipper, NULL);
if (FAILED(hr)) {
TRACE("Error: CreateClipper\n");
TraceErrorDD(hr);
return 1;
}
// Assign your window's HWND to the clipper
ddWnd = AfxGetMainWnd()->GetSafeHwnd();
hr = pClipper->SetHWnd(0, ddWnd);
if (FAILED(hr)) {
TRACE("Error: SetHWnd\n");
TraceErrorDD(hr);
return 2;
}
// Attach the clipper to the primary surface
hr = pDDSPrimary->SetClipper(pClipper);
if (FAILED(hr)) {
TRACE("Error: SetClipper\n");
TraceErrorDD(hr);
return 3;
}
// success
return 0;
}
BOOL CDirectDrawApp::InitInstance()
{
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
LoadStdProfileSettings(0);
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CDirectDrawDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CDirectDrawView));
AddDocTemplate(pDocTemplate);
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo))
return FALSE;
InitDirectXGlobals();
InitDDraw();
SetMode();
// These will be coming soonish
// TRACE("Calling LoadJascPalette\n");
// LoadJascPalette("inspect.pal", 10, 240);
TRACE("Calling CreatePrimarySurface\n");
CreatePrimarySurface();
TRACE("Calling CreateClipper\n");
CreateClipper();
// Also coming soonish
// TRACE("Calling AttachPalette\n");
// AttachPalette(pDDPal);
// Start the animation
bAnimating = TRUE;
return TRUE;
}
// Checks if the memory associated with surfaces
// is lost and restores if necessary.
// Not sure about fullscreen/windowed;
// I'll get back to you people on this :)
BOOL CheckSurfaces()
{
// Check the primary surface
if (pDDSPrimary) {
if (pDDSPrimary->IsLost() == DDERR_SURFACELOST) {
pDDSPrimary->Restore();
return FALSE;
}
}
return TRUE;
}
BOOL CDirectDrawApp::OnIdle(LONG lCount)
{
CWinApp::OnIdle(lCount); // Call the previous default handler
if (bAnimating) {
// Our game's heartbeat function
HeartBeat();
// prevent's too much flicker. We'll need a smarter system
// soon, this one is temporary
Sleep(50);
}
// request more idle-time, so that we can render the next loop!
return TRUE;
}
BOOL CDirectDrawApp::HeartBeat()
{
// Variables for the blocks color, in RGB format
static r = 0;
static g = 100;
static b = 150;
r++;
g += 3;
b += 2;
if (r > 255) r = 0;
if (g > 255) g = 0;
if (b > 255) b = 0;
// The destination rectangle on my 320x240 off-screen surface
CRect rc(10,30,100,70);
// We draw the rectangle using a blit.
// This structure describes how to do the blit.
DDBLTFX fx;
// Zero out all fields of the blit effects structure
memset(&fx, 0, sizeof(fx));
// The dwSize field must contain the size of the structure
fx.dwSize = sizeof(DDBLTFX);
// Set the color we want to draw the rectangle
fx.dwFillColor = RGB(r,g,b);
// Blit. Note that we blit to the back buffer
HRESULT hr;
hr = pDDSBack->Blt(&rc, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT,
&fx);
if (FAILED(hr)) {
TRACE("Error blitting: ");
TraceErrorDD(hr);
return FALSE;
}
// Call our routine for flipping the surfaces
FlipSurfaces();
// No major errors
return TRUE;
}
Note that Blt parameter DDBLT_WAIT. If a surface is busy then DirectDraw will return an error, without performing the blit. Passing the DDBLT_WAIT option will instruct DirectDraw to wait until the surface becomes available and then perform the blit.
UINT FlipSurfaces()
{
HRESULT hr;
// source and destination rectangles
RECT rcSrc;
RECT rcDest;
POINT p;
// Make sure no surfaces have been lost
CheckSurfaces();
// if we're windowed do the blit, else just Flip
if (!bFullScreen)
{
// find out where on the primary surface our window lives
p.x = 0; p.y = 0;
::ClientToScreen(ddWnd, &p);
::GetClientRect(ddWnd, &rcDest);
OffsetRect(&rcDest, p.x, p.y);
SetRect(&rcSrc, 0, 0, 320, 240);
hr = pDDSPrimary->Blt(&rcDest, pDDSBack, &rcSrc, DDBLT_WAIT,
NULL);
} else {
hr = pDDSPrimary->Flip(NULL, DDFLIP_WAIT);
}
// success!
return 0;
}
void TraceErrorDD(HRESULT hErr)
{
switch (hErr)
{
case DDERR_ALREADYINITIALIZED:
TRACE("DDERR_ALREADYINITIALIZED"); break;
case DDERR_CANNOTATTACHSURFACE:
TRACE("DDERR_CANNOTATTACHSURFACE"); break;
case DDERR_CANNOTDETACHSURFACE:
TRACE("DDERR_CANNOTDETACHSURFACE"); break;
case DDERR_CURRENTLYNOTAVAIL:
TRACE("DDERR_CURRENTLYNOTAVAIL"); break;
case DDERR_EXCEPTION:
TRACE("DDERR_EXCEPTION"); break;
case DDERR_GENERIC:
TRACE("DDERR_GENERIC"); break;
case DDERR_HEIGHTALIGN:
TRACE("DDERR_HEIGHTALIGN"); break;
case DDERR_INCOMPATIBLEPRIMARY:
TRACE("DDERR_INCOMPATIBLEPRIMARY"); break;
case DDERR_INVALIDCAPS:
TRACE("DDERR_INVALIDCAPS"); break;
case DDERR_INVALIDCLIPLIST:
TRACE("DDERR_INVALIDCLIPLIST"); break;
case DDERR_INVALIDMODE:
TRACE("DDERR_INVALIDMODE"); break;
case DDERR_INVALIDOBJECT:
TRACE("DDERR_INVALIDOBJECT"); break;
case DDERR_INVALIDPARAMS:
TRACE("DDERR_INVALIDPARAMS"); break;
case DDERR_INVALIDPIXELFORMAT:
TRACE("DDERR_INVALIDPIXELFORMAT"); break;
case DDERR_INVALIDRECT:
TRACE("DDERR_INVALIDRECT"); break;
case DDERR_LOCKEDSURFACES:
TRACE("DDERR_LOCKEDSURFACES"); break;
case DDERR_NO3D:
TRACE("DDERR_NO3D"); break;
case DDERR_NOALPHAHW:
TRACE("DDERR_NOALPHAHW"); break;
case DDERR_NOCLIPLIST:
TRACE("DDERR_NOCLIPLIST"); break;
case DDERR_NOCOLORCONVHW:
TRACE("DDERR_NOCOLORCONVHW"); break;
case DDERR_NOCOOPERATIVELEVELSET:
TRACE("DDERR_NOCOOPERATIVELEVELSET"); break;
case DDERR_NOCOLORKEY:
TRACE("DDERR_NOCOLORKEY"); break;
case DDERR_NOCOLORKEYHW:
TRACE("DDERR_NOCOLORKEYHW"); break;
case DDERR_NODIRECTDRAWSUPPORT:
TRACE("DDERR_NODIRECTDRAWSUPPORT"); break;
case DDERR_NOEXCLUSIVEMODE:
TRACE("DDERR_NOEXCLUSIVEMODE"); break;
case DDERR_NOFLIPHW:
TRACE("DDERR_NOFLIPHW"); break;
case DDERR_NOGDI:
TRACE("DDERR_NOGDI"); break;
case DDERR_NOMIRRORHW:
TRACE("DDERR_NOMIRRORHW"); break;
case DDERR_NOTFOUND:
TRACE("DDERR_NOTFOUND"); break;
case DDERR_NOOVERLAYHW:
TRACE("DDERR_NOOVERLAYHW"); break;
case DDERR_NORASTEROPHW:
TRACE("DDERR_NORASTEROPHW"); break;
case DDERR_NOROTATIONHW:
TRACE("DDERR_NOROTATIONHW"); break;
case DDERR_NOSTRETCHHW:
TRACE("DDERR_NOSTRETCHHW"); break;
case DDERR_NOT4BITCOLOR:
TRACE("DDERR_NOT4BITCOLOR"); break;
case DDERR_NOT4BITCOLORINDEX:
TRACE("DDERR_NOT4BITCOLORINDEX"); break;
case DDERR_NOT8BITCOLOR:
TRACE("DDERR_NOT8BITCOLOR"); break;
case DDERR_NOTEXTUREHW:
TRACE("DDERR_NOTEXTUREHW"); break;
case DDERR_NOVSYNCHW:
TRACE("DDERR_NOVSYNCHW"); break;
case DDERR_NOZBUFFERHW:
TRACE("DDERR_NOZBUFFERHW"); break;
case DDERR_NOZOVERLAYHW:
TRACE("DDERR_NOZOVERLAYHW"); break;
case DDERR_OUTOFCAPS:
TRACE("DDERR_OUTOFCAPS"); break;
case DDERR_OUTOFMEMORY:
TRACE("DDERR_OUTOFMEMORY"); break;
case DDERR_OUTOFVIDEOMEMORY:
TRACE("DDERR_OUTOFVIDEOMEMORY"); break;
case DDERR_OVERLAYCANTCLIP:
TRACE("DDERR_OVERLAYCANTCLIP"); break;
case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
TRACE("DDERR_OVERLAYCOLORKEYONLYONEACTIVE"); break;
case DDERR_PALETTEBUSY:
TRACE("DDERR_PALETTEBUSY"); break;
case DDERR_COLORKEYNOTSET:
TRACE("DDERR_COLORKEYNOTSET"); break;
case DDERR_SURFACEALREADYATTACHED:
TRACE("DDERR_SURFACEALREADYATTACHED"); break;
case DDERR_SURFACEALREADYDEPENDENT:
TRACE("DDERR_SURFACEALREADYDEPENDENT"); break;
case DDERR_SURFACEBUSY:
TRACE("DDERR_SURFACEBUSY"); break;
case DDERR_CANTLOCKSURFACE:
TRACE("DDERR_CANTLOCKSURFACE"); break;
case DDERR_SURFACEISOBSCURED:
TRACE("DDERR_SURFACEISOBSCURED"); break;
case DDERR_SURFACELOST:
TRACE("DDERR_SURFACELOST"); break;
case DDERR_SURFACENOTATTACHED:
TRACE("DDERR_SURFACENOTATTACHED"); break;
case DDERR_TOOBIGHEIGHT:
TRACE("DDERR_TOOBIGHEIGHT"); break;
case DDERR_TOOBIGSIZE:
TRACE("DDERR_TOOBIGSIZE"); break;
case DDERR_TOOBIGWIDTH:
TRACE("DDERR_TOOBIGWIDTH"); break;
case DDERR_UNSUPPORTED:
TRACE("DDERR_UNSUPPORTED"); break;
case DDERR_UNSUPPORTEDFORMAT:
TRACE("DDERR_UNSUPPORTEDFORMAT"); break;
case DDERR_UNSUPPORTEDMASK:
TRACE("DDERR_UNSUPPORTEDMASK"); break;
case DDERR_VERTICALBLANKINPROGRESS:
TRACE("DDERR_VERTICALBLANKINPROGRESS"); break;
case DDERR_WASSTILLDRAWING:
TRACE("DDERR_WASSTILLDRAWING"); break;
case DDERR_XALIGN:
TRACE("DDERR_XALIGN"); break;
case DDERR_INVALIDDIRECTDRAWGUID:
TRACE("DDERR_INVALIDDIRECTDRAWGUID"); break;
case DDERR_DIRECTDRAWALREADYCREATED:
TRACE("DDERR_DIRECTDRAWALREADYCREATED"); break;
case DDERR_NODIRECTDRAWHW:
TRACE("DDERR_NODIRECTDRAWHW"); break;
case DDERR_PRIMARYSURFACEALREADYEXISTS:
TRACE("DDERR_PRIMARYSURFACEALREADYEXISTS"); break;
case DDERR_NOEMULATION:
TRACE("DDERR_NOEMULATION"); break;
case DDERR_REGIONTOOSMALL:
TRACE("DDERR_REGIONTOOSMALL"); break;
case DDERR_CLIPPERISUSINGHWND:
TRACE("DDERR_CLIPPERISUSINGHWND"); break;
case DDERR_NOCLIPPERATTACHED:
TRACE("DDERR_NOCLIPPERATTACHED"); break;
case DDERR_NOHWND:
TRACE("DDERR_NOHWND"); break;
case DDERR_HWNDSUBCLASSED:
TRACE("DDERR_HWNDSUBCLASSED"); break;
case DDERR_HWNDALREADYSET:
TRACE("DDERR_HWNDALREADYSET"); break;
case DDERR_NOPALETTEATTACHED:
TRACE("DDERR_NOPALETTEATTACHED"); break;
case DDERR_NOPALETTEHW:
TRACE("DDERR_NOPALETTEHW"); break;
case DDERR_BLTFASTCANTCLIP:
TRACE("DDERR_BLTFASTCANTCLIP"); break;
case DDERR_NOBLTHW:
TRACE("DDERR_NOBLTHW"); break;
case DDERR_NODDROPSHW:
TRACE("DDERR_NODDROPSHW"); break;
case DDERR_OVERLAYNOTVISIBLE:
TRACE("DDERR_OVERLAYNOTVISIBLE"); break;
case DDERR_NOOVERLAYDEST:
TRACE("DDERR_NOOVERLAYDEST"); break;
case DDERR_INVALIDPOSITION:
TRACE("DDERR_INVALIDPOSITION"); break;
case DDERR_NOTAOVERLAYSURFACE:
TRACE("DDERR_NOTAOVERLAYSURFACE"); break;
case DDERR_EXCLUSIVEMODEALREADYSET:
TRACE("DDERR_EXCLUSIVEMODEALREADYSET"); break;
case DDERR_NOTFLIPPABLE:
TRACE("DDERR_NOTFLIPPABLE"); break;
case DDERR_CANTDUPLICATE:
TRACE("DDERR_CANTDUPLICATE"); break;
case DDERR_NOTLOCKED:
TRACE("DDERR_NOTLOCKED"); break;
case DDERR_CANTCREATEDC:
TRACE("DDERR_CANTCREATEDC"); break;
case DDERR_NODC:
TRACE("DDERR_NODC"); break;
case DDERR_WRONGMODE:
TRACE("DDERR_WRONGMODE"); break;
case DDERR_IMPLICITLYCREATED:
TRACE("DDERR_IMPLICITLYCREATED"); break;
case DDERR_NOTPALETTIZED:
TRACE("DDERR_NOTPALETTIZED"); break;
case DDERR_UNSUPPORTEDMODE:
TRACE("DDERR_UNSUPPORTEDMODE"); break;
case DDERR_NOMIPMAPHW:
TRACE("DDERR_NOMIPMAPHW"); break;
case DDERR_INVALIDSURFACETYPE:
TRACE("DDERR_INVALIDSURFACETYPE"); break;
case DDERR_DCALREADYCREATED:
TRACE("DDERR_DCALREADYCREATED"); break;
case DDERR_CANTPAGELOCK:
TRACE("DDERR_CANTPAGELOCK"); break;
case DDERR_CANTPAGEUNLOCK:
TRACE("DDERR_CANTPAGEUNLOCK"); break;
case DDERR_NOTPAGELOCKED:
TRACE("DDERR_NOTPAGELOCKED"); break;
case DDERR_NOTINITIALIZED:
TRACE("DDERR_NOTINITIALIZED"); break;
default:
TRACE("Unknown Error"); break;
}
TRACE("\n");
}
Article updated: 2 September 1997
Article by David Joffe
http://www.geocities.com/SoHo/Lofts/2018/