Main Site Links Resources Tutorials
News VB Gaming Code Downloads DirectX 7
Contact Webmaster VB Programming Product Reviews DirectX 8
  General Multimedia Articles DirectX 9
      Miscellaneous

DirectDraw: Enumeration
By: Jack Hoxley
Written: May 2000

Download: DD_Enum.Zip (165kb)


Enumeration is a very important process and any professional application should use it.

Assuming that you've done (or know about) DirectDraw Fullscreen mode, you will be aware that you need to specify a screen width, height and colour depth. If you're using one of the common resolutions (640x480, 800x600) then you can be fairly confident that most computers will support that resolution. But you can't be 100% sure.

Enumeration is the process of checking the available capabilities; it is widely used in DirectX and it is good practise to use it. Using enumeration you can collect information on what display modes are available and what colour depths can be used; more importantly when you get onto the higher level functions, particularly hardware specific functions - You can use enumeration to check the computer to see if it is capable of doing what you want it to do. It can also be used a a safety net; for example, if you attempt to use a gamma control and the hardware does not support it you'll get errors and your program can crash. If, before hand, you'd enumerated the hardware you will know that the hardware does/doesn't support gamma controls.

Enumeration is used by all the big games, look through any popular game and you'll see various options relating to hardware - use Triple-buffering, use 32bit textures, use 32bit display modes, enable 3D sound... and so on. This is all done through enumeration.

The Code
This tutorial will cover the basics of enumeration. At the end of this tutorial you will have a simple program that lists the important hardware capabilites of the current computer and the available display modes.

Step 1: The interface
It is probably easier if you download the above zip file for this part, but if you can't/won't then follow these steps.
1. Add two frames to the form, as shown in the picture. Make the captions "Display Mode" and "Other Details".
2. Add a dropdown combo box to the first frame, name it "cmbArray" and makes it's "style" property to equal 2 Add the label in if you want to - but it isn't necessary.
3. Add a Label to the same frame and call it lblinfo
4. Add a Listbox to the second frame and call it "lstHardware"
5. Add a command button outside the two frames and at the bottom of the window.
6. Make the command button have a caption of "Run A Test DirectDraw Application in the selected Display Mode"
You're window should now look something like:

Step 2: The Variables
The varaibles are almost identical to the fullscreen tutorial - Apart from the top two sections it is identical. As is a lot of the code. For more information on the variables, see the fullscreen mode tutorial.

Dim dx As New DirectX7

'This data structure is to simplify getting/using the display
'modes AFTER they have been enumerated.

Private Type DisplayModeDesc
Width As Long
Height As Long
BPP As Byte
End Type
Dim arr_DisplayModes() As DisplayModeDesc 'note the fact that I haven't
'specified how big the array is to be. This allows me to resize it later on.



Dim binit As Boolean
Dim dd As DirectDraw7
Dim Mainsurf As DirectDrawSurface7
Dim primary As DirectDrawSurface7
Dim backbuffer As DirectDrawSurface7
Dim ddsd1 As DDSURFACEDESC2
Dim ddsd2 As DDSURFACEDESC2
Dim ddsd3 As DDSURFACEDESC2
Dim ddsd4 As DDSURFACEDESC2
Dim brunning As Boolean
Dim CurModeActiveStatus As Boolean
Dim bRestore As Boolean

Step 3: The procedures
This section is for all the core-code procedures. All apart from two are directly copied from the DirectDraw: Fullscreen mode tutorial, but most of the comments have been taken out. Please go to the Fullscreen tutorial for a full explanation

Sub Init()
On Local Error GoTo errOut 'If there is an error we end the program.
Set dd = dx.DirectDrawCreate("")
frmDummy.Show

Call dd.SetCooperativeLevel(frmDummy.hWnd, DDSCL_FULLSCREEN Or DDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE)

Dim reqWidth As Long, reqHeight As Long, reqDepth As Byte
reqWidth = arr_DisplayModes(cmbArray.ListIndex + 1).Width
reqHeight = arr_DisplayModes(cmbArray.ListIndex + 1).Height
reqDepth = arr_DisplayModes(cmbArray.ListIndex + 1).BPP
Call dd.SetDisplayMode(reqWidth, reqHeight, reqDepth, 0, DDSDM_DEFAULT)

ddsd1.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT
ddsd1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP Or DDSCAPS_COMPLEX ddsd1.lBackBufferCount = 1
Set primary = dd.CreateSurface(ddsd1)

'Get the backbuffer

Dim caps As DDSCAPS2
caps.lCaps = DDSCAPS_BACKBUFFER
Set backbuffer = primary.GetAttachedSurface(caps)
backbuffer.GetSurfaceDesc ddsd3

backbuffer.SetFontTransparency True
backbuffer.SetForeColor RGB(0, 0, 0)

' init the surfaces
InitSurfaces


binit = True
brunning = True
Do While brunning
blt
DoEvents
Loop

errOut:
EndIt
End Sub

Sub blt()
On Local Error GoTo errOut
If binit = False Then Exit Sub

Dim ddrval As Long
Dim rBack As RECT

bRestore = False
Do Until ExModeActive
DoEvents
bRestore = True
Loop

' if we lost and got back the surfaces, then restore them

DoEvents
If bRestore Then bRestore = False
dd.RestoreAllSurfaces
InitSurfaces
End If

'get the area of the screen where our window is
'this sets the rectangle to be the size of the screen.

rBack.Bottom = ddsd3.lHeight
rBack.Right = ddsd3.lWidth

ddrval = backbuffer.BltFast(0, 0, Mainsurf, rBack, DDBLTFAST_WAIT)

Call backbuffer.DrawText(10, 10, "Press Any Key To Continue", False)

'flip the back buffer to the screen
primary.Flip Nothing, DDFLIP_WAIT

errOut:
End Sub

Sub EndIt()
Call dd.RestoreDisplayMode
Call dd.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL)
Unload frmDummy
End Sub

Function ExModeActive() As Boolean
'This is used to test if we're in the correct resolution.
Dim TestCoopRes As Long
TestCoopRes = dd.TestCooperativeLevel
If (TestCoopRes = DD_OK) Then
ExModeActive = True
Else
ExModeActive = False
End If
End Function

Sub InitSurfaces()
Set Mainsurf = Nothing

'load the bitmap into a surface - backdrop.bmp
ddsd4.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH
ddsd4.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
ddsd4.lWidth = ddsd3.lWidth
ddsd4.lHeight = ddsd3.lHeight
Set Mainsurf = dd.CreateSurfaceFromFile(App.Path & "\backdrop.bmp", ddsd4)
End Sub

Sub GetDisplayModes()
'This is the actual code that reports back what display modes are available.
'You could modify this to be a function, which enumerates the display modes
'and runs through the list until it finds the one that you want. ie. You're program
'runs in 800x600 in 32bpp mode; create a function that searches through the
'available modes UNTIL it finds the one you want (800x600x32), at this point it
'reports back True or false......


Dim DisplayModesEnum As DirectDrawEnumModes
Dim ddsd2 As DDSURFACEDESC2
Dim dd As DirectDraw7 'These two lines can also be seen in the Init sub. This time
'it doesn't go to fullscreen mode

Set dd = dx.DirectDrawCreate("")
dd.SetCooperativeLevel Me.hWnd, DDSCL_NORMAL

'Create the Enumeration object
Set DisplayModesEnum = dd.GetDisplayModesEnum(0, ddsd2)
'Remember the array that wasn't defined? At this point
'we set the size of the array.

ReDim arr_DisplayModes(DisplayModesEnum.GetCount()) As DisplayModeDesc

'This loop runs through the display modes, retrieving the data.
'Height/Width/BPP aren't the only things that you can retrieve here....

For i = 1 To DisplayModesEnum.GetCount()
DisplayModesEnum.GetItem i, ddsd2
cmbArray.AddItem CStr(ddsd2.lWidth) & "x" & CStr(ddsd2.lHeight) & " " & Str(ddsd2.ddpfPixelFormat.lRGBBitCount) & "bpp"
cmbArray.Text = CStr(ddsd2.lWidth) & "x" & CStr(ddsd2.lHeight) & " " & CStr(ddsd2.ddpfPixelFormat.lRGBBitCount) & "bpp"

'This fills out the data structure to include information
'on the current display mode.

arr_DisplayModes(i).Height = ddsd2.lHeight
arr_DisplayModes(i).Width = ddsd2.lWidth
arr_DisplayModes(i).BPP = ddsd2.ddpfPixelFormat.lRGBBitCount
Next i

'Directdraw is no longer needed - destroy it.

Set dd = Nothing

'Fill out the user-display label

lblinfo.Caption = "Display Mode index = " & cmbArray.ListIndex + 1 & vbCr
lblinfo.Caption = lblinfo.Caption & " Height = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Height) & vbCr lblinfo.Caption = lblinfo.Caption & " Width = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Width) & vbCr lblinfo.Caption = lblinfo.Caption & " Colour Depth = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).BPP) & vbCr
End Sub

Sub GetDDCaps()
'This part returns the capabilities of DirectDraw
'You only really need this information if you're going to do
'any technical stuff.

Dim dd As DirectDraw7
Dim hwCaps As DDCAPS 'HARDWARE
Dim helCaps As DDCAPS 'SOFTWARE EMULATION

Set dd = dx.DirectDrawCreate("")
dd.SetCooperativeLevel Me.hWnd, DDSCL_NORMAL
dd.GetCaps hwCaps, helCaps

'how much video memory is available
lstHardware.AddItem "GENERAL INFORMATION"
'The memory amount can be useful. If you know that you're surfaces require
'450kb of memory then you can check if the host computer has this much memory.

lstHardware.AddItem " total video memory " & CStr(hwCaps.lVidMemTotal) & " bytes (" & CStr(Format$(hwCaps.lVidMemTotal / 1024, "#.0")) & "Kb)"
lstHardware.AddItem " free video memory " & CStr(hwCaps.lVidMemFree) & " bytes (" & CStr(Format$(hwCaps.lVidMemFree / 1024, "#.0")) & "Kb)"

lstHardware.AddItem " There are " & hwCaps.lNumFourCCCodes & " FourCC codes available"
lstHardware.AddItem ""

lstHardware.AddItem "HARDWARE CAPABILITIES"

'You can get a list of what these constants mean in the
'sdk help file. If you don't have the help file you're a bit stuck!

lVal = hwCaps.ddsCaps.lCaps2
If lVal And DDCAPS2_CANCALIBRATEGAMMA Then
lstHardware.AddItem " Supports gamma correction"
Else
lstHardware.AddItem " No support for gamma correction"
End If

If lVal And DDCAPS2_CERTIFIED Then
lstHardware.AddItem " The driver is certified"
Else
lstHardware.AddItem " The driver is not certified"
End If

If lVal And DDCAPS2_WIDESURFACES Then
lstHardware.AddItem " support for surfaces wider than the screen"
Else
lstHardware.AddItem " No support for surfaces wider than the screen"
End If

lVal = hwCaps.lSVBFXCaps
If lVal And DDFXCAPS_BLTALPHA Then
lstHardware.AddItem " Support for Alpha Blended Blit operations"
Else
lstHardware.AddItem " No support for Alpha Blended Blit operations"
End If

If lVal And DDFXCAPS_BLTROTATION Then
lstHardware.AddItem " Support for rotation Blit operations"
Else
lstHardware.AddItem " No support for rotation Blit operations"
End If

lVal = hwCaps.lSSBCaps
If lVal And DDCAPS_3D Then
lstHardware.AddItem " Support for 3D Acceleration"
Else
lstHardware.AddItem " No support for 3D acceleration"
End If

If lVal And DDCAPS_BLTQUEUE Then
lstHardware.AddItem " Support for asynchronous blitting"
Else
lstHardware.AddItem " No support for asynchronous blitting"
End If

If lVal And DDCAPS_BLTSTRETCH Then
lstHardware.AddItem " Support for stretching during Blit operations"
Else
lstHardware.AddItem " No support for stretching during blit operations"
End If

If lVal And DDCAPS_NOHARDWARE Then
lstHardware.AddItem " Hardware support is available"
Else
lstHardware.AddItem " No hardware support"
End If

'//////////////////////SOFTWARE\\\\\\\\\\\\\\\\\\\\\\\\\\\\

lstHardware.AddItem "SOFTWARE CAPABILITIES"

lVal = helCaps.ddsCaps.lCaps2
If lVal And DDCAPS2_WIDESURFACES Then
lstHardware.AddItem " The device supports surfaces wider than the screen"
Else
lstHardware.AddItem " The device does not support surfaces wider than the screen"
End

If lVal = helCaps.lSVBFXCaps
If lVal And DDFXCAPS_BLTALPHA Then
lstHardware.AddItem " Software supports Alpha Blended Blit operations"
Else
lstHardware.AddItem " No Software support for Alpha Blended Blit operations"
End If

If lVal And DDFXCAPS_BLTROTATION Then
lstHardware.AddItem " Software supports rotation Blit operations"
Else
lstHardware.AddItem " No software support for rotation Blit operations"
End If

lVal = helCaps.lSSBCaps
If lVal And DDCAPS_3D Then
lstHardware.AddItem " Software supports 3D Acceleration"
Else
lstHardware.AddItem " No software support for 3D acceleration"
End If

If lVal And DDCAPS_BLTQUEUE Then
lstHardware.AddItem " Software supports asynchronous blitting"
Else
lstHardware.AddItem " No software support for asynchronous blitting"
End If

Set dd = Nothing

End Sub

Step 4: Linking code and interface code
This is the last section of this tutorial. It deals with linking the procedures together and finishing off the interface.

'These Next three procedures just update the user-display with the
'information he/she has just selected.

Private Sub cmbArray_Click()
lblinfo.Caption = "Display Mode index = " & cmbArray.ListIndex + 1 & vbCr
lblinfo.Caption = lblinfo.Caption & " Height = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Height) & vbCr lblinfo.Caption = lblinfo.Caption & " Width = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Width) & vbCr lblinfo.Caption = lblinfo.Caption & " Colour Depth = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).BPP) & vbCr
End Sub

Private Sub cmbArray_KeyDown(KeyCode As Integer, Shift As Integer)
lblinfo.Caption = "Display Mode index = " & cmbArray.ListIndex + 1 & vbCr
lblinfo.Caption = lblinfo.Caption & " Height = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Height) & vbCr lblinfo.Caption = lblinfo.Caption & " Width = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Width) & vbCr lblinfo.Caption = lblinfo.Caption & " Colour Depth = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).BPP) & vbCr
End Sub

Private Sub cmbArray_Scroll()
lblinfo.Caption = "Display Mode index = " & cmbArray.ListIndex + 1 & vbCr
lblinfo.Caption = lblinfo.Caption & " Height = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Height) & vbCr lblinfo.Caption = lblinfo.Caption & " Width = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).Width) & vbCr lblinfo.Caption = lblinfo.Caption & " Colour Depth = " & CStr(arr_DisplayModes(cmbArray.ListIndex + 1).BPP) & vbCr
End Sub

Private Sub Command1_Click()
'This will start the test display mode
Init
End Sub

Private Sub Form_Load()
Me.Show
'This lists the display modes
GetDisplayModes
'This lists the hardware/software CAPabilities
GetDDCaps
End Sub

Step 5: frmDummy.frm
One last thing, the dummy form. This is used by DirectDraw when it goes to fullscreen mode. It is a simple form with these attributes:
1. Pixel Scale Mode
2. Maximises when loaded
3. No Caption or control box.

The only code that is needed for this form is to make it disappear, when the test resolution is run the user has to press any key before it will close again.

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Call frmMain.EndIt
End Sub

Simple as that. The endit procedure was written into the other form, and this just makes a call to that code. The form_Keydown event is called whenever the user presses any key (and our window has the focus).

Step 6: A Recursive Function
It should be fairly easy to make a recursive function that searches for a particular resolution. Try this following code, everything is contained within a single module, and is designed to be added into your projects.

Private enum_dx As New DirectX7
Private enum_DModes As DirectDrawEnumModes
Private enum_ddsd As DDSURFACEDESC2
Private enum_dd As DirectDraw7
Private enum_i As Integer

Public Function FindResolution(reqWidth As Long, reqHeight As Long, reqBPP As Byte, oHostForm As Form) As Boolean
Set enum_dd = enum_dx.DirectDrawCreate("")
enum_dd.SetCooperativeLevel oHostForm.hWnd, DDSCL_NORMAL
Set enum_DModes = enum_dd.GetDisplayModesEnum(0, enum_ddsd)
FindResolution = False
For enum_i = 1 To enum_DModes.GetCount()
enum_DModes.GetItem enum_i, enum_ddsd
If CLng(enum_ddsd.lHeight) = CLng(reqHeight) Then
If CLng(enum_ddsd.lWidth) = CLng(reqWidth) Then
If CLng(enum_ddsd.ddpfPixelFormat.lRGBBitCount) = CLng(reqBPP) Then
FindResolution = True
Exit Function
End If
End If
End If
Next enum_i
Set enum_dd = Nothing
End Function

Although this isn't the simplest code, it is almost identical to the code used earlier; this time it has none of the array methods or user-interface code - this function is intended to go on in the background with no intervention by the user.

Feel free to use this procedure in your DirectDraw projects.

Finished

DirectX 4 VB 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster