Screen Resolutions

Tuesday Nov 19th 2002 by Steve Anderson
Share:

Screen Resolutions

It can often be useful to be able to retrieve or change the screen resolution direct from your VB application. For example, if you have written a game in VB, you may wish to set the screen resolution to 600x480. Desktop Publishing software would also benefit from being able to offer the user a one-click function to change the screen size.

You could even design a dynamic application that resizes all the controls on the form based on the current screen resolution.

This article will take you through some of the more important display setting functions that will prove valuable to the Visual Basic programmer.

Normally manipulating and displaying information on the display settings this would be done with the aid of the Display Properties applet in the control panel, but this article will teach you how to do the same programmatically using the Windows API.

Click here for a larger image.

The Display Settings Control Panel

For example if you design a program that uses 800 pixels by 600 pixels and the user of the machine running your application has their screen size set to 640 pixels by 480 pixels, 1024 pixels by 768 pixels or higher then your application may not be displayed correctly.

If you determine the screen resolution then you can warn the user that their display settings may effect the functionality of your application. You could, if you the user wanted, use the method later in this article that will let you dynamically change the resolution for the user and then on exit of you application set the resolution back to the previous state.

The API function that returns system metrics, including the screen resolution, is the GetSystemMetrics API function. It contains only one parameter.

nIndex – This parameter specifies the metric or configuration setting that you want to retrieve. Although there are over 150 constants that you can use for this parameter, in this article I will explain how to use just two of them to retrieve the vertical and horizontal reoulution of the screen. (For a full list of constants, check out this tip)

Constant Description
SM_CXSCREEN You may have noticed that the constant with CX in it is for the x axis or horizontal axis if you prefer to call it that. The simply returns the width of the screen, which for most users is 800 pixels by 600 pixels.
SM_CYSCREEN This is simply the opposite of SM_CXSCREEN, and is the height of the screen or the y-axis of the screen in algebraic form.

To use this API function simply call it by:

<Variable> = GetSystemMetrics(<Constant>)

The API function will then return the value depending on the constant you have used.

To return the screen resolution you can construct a simple function from the information above:

Public Function GetScreenResolution() As String
GetScreenResolution = GetSystemMetrics(SM_CXSCREEN) & _
" pixels by " & GetSystemMetrics(SM_CYSCREEN) & " pixels"
End Function

Now you can change this function to what ever you like. One possible change that you may make would to be to check that the user has the 800 pixels by 600 pixels screen resolution set. You could do this by returning true to the function if the user has a 800 pixels by 600 pixels screen resolution and vice versa. Below is an example of this

' Check whether screen resolution is set to 800x600
' Returns True if the resolution is at 800x600 else
' False is returned

Public Function GetScreenResolution() As Boolean
Dim lTemp As String
' Temporary string to hold returned screen
' resolution
lTemp = GetSystemMetrics(SM_CXSCREEN) & _
"x" & GetSystemMetrics(SM_CYSCREEN)
' Call the API function twice to return
' screen size for each axis as format into
' the temporary string
If lTemp = "800x600" Then
  ' Check whether resolution is set to 800x600
  GetScreenResolution = True
  ' True
Else
  GetScreenResolution = False
  ' False
End If
End Function

You should now be able to implement this into your application for your own needs.

The functions here are demonstrated in the GetScreenRes demo project.

Now that you have know how to retrieve the screen resolution you may want to know how you can retrieve the number of colours that is available to Windows. The options are: 16 colours, 4 bit; 256 colours,8 bit; 65536 colours, 16 bit; 16.7 million colours, either 24 bit or 32 bit.

GetDeviceCaps

This API function is important in retrieving the number of colours that is available to windows. It returns the information on a given index. The paramters are:

Hdc – This is the handle of the device context that you find by using CreateIC.

nIndex – This is the information that you want to retrieve from the display driver. The constants that are important in this section of the article are

Constant Description
BITSPIXEL This is the number of bits that are available per pixel. This will return 4, 8, 16, 24 or 32.
PLANES This returns the number of colour planes

CreateIC

This API function is used to create a device context, which allows easy access to device information. This CreateIC API function has these parameters:

LpDriverName – This specifies the name of the driver that you want to retrieve information on. This is usually ‘Display’ for information on the display driver.

LpDeviceName – This should be left as null

LpOutput – This should be left as null

LpInitData – This should be left as null

DeleteDC

This simply deletes the device context that was created by using CreateIC. You must do this for every device context that you create in order to free up Windows resources.

To retrieve the number of colours that are available to Windows we first need to find out how many planes are available to windows, which will be either 1 or 4. Most machines will support 1 plane.

This function returns the number of colours and colour depth as a string:

Private Const BITSPIXEL = 12
Private Const PLANES = 14

Private Declare Function CreateIC Lib "gdi32" _
Alias "CreateICA" (ByVal lpDriverName As String, _
ByVal lpDeviceName As Any, ByVal lpOutput As Any, _
ByVal lpInitData As Any) As Long

Private Declare Function GetDeviceCaps Lib "gdi32" _
(ByVal hdc As Long, ByVal nIndex As Long) As Long

Private Declare Function DeleteDC Lib "gdi32" _
(ByVal hdc As Long) As Long

Public Function GetAvailableColours() As String
Dim lHdc As Long, lPlanes As Long, lBitsPerPixel As Integer
' Declare variables
lHdc = CreateIC("DISPLAY", 0&, 0&, 0&)
' Create the device context for the display
If lHdc = 0 Then
  ' An error has occurred and the function will exit
  GetAvailableColours = "Error"
Exit Function
End If

lPlanes = GetDeviceCaps(lHdc, PLANES)
' Return info on number of planes

lBitsPerPixel = GetDeviceCaps(lHdc, BITSPIXEL)
' Use display device 
' context to return info on the
' number of pixels

lHdc = DeleteDC(lHdc)
' Delete the device context

Select Case lPlanes

Case 1

' 1 plane is available. This 
' will be the same for most
' computer systems

Select Case lBitsPerPixel
' Select the number of colours available
Case 4: GetAvailableColours = _
"4 Bit, 16 Colours"
Case 8: GetAvailableColours = _
"8 Bit, 256 Colours"
Case 16: GetAvailableColours = _
"16 Bit, 65536 Colours"
Case 24: GetAvailableColours = _
"24 Bit True Colour, 16.7 Million Colours"
Case 32: GetAvailableColours = _
"32 Bit True Colour, 16.7 Million Colours"
End Select

Case 4
GetAvailableColours = "16 Bit, 65536 Colours"
' If there are 4 planes then the availible
' colours will be 16-bit
Case Else

GetAvailableColours = "Undetermined"
' The number of colours could not bee determined

End Select

End Function

The functions here are demonstrated in the GetColourDepth demo project.

Now that you can retrieve both the current screen resolutions and number of colours that are selected in Windows, you will want to know how you can enumerate the resolutions and colour modes that a machine supports. This can be very useful especially with changing the screen resolution programmatically, as you must know whether the computer supports it.

EnumDisplaySettings

This API function retrieves information about the display driver’s graphics modes. There are three parameters:

LpszDeviceName – Leave this as null (0&)

IModeNum = This is the index of the display mode that you want to retrieve information about, starting with 0. You call this in a sequence, and it will continue returning modes until 0 is returned by the API function.

PDevMode – This parameter points to a DevMode type structure in which to retrieve information about the graphics modes that are available.

The following properties of the DevMode structure will be retrieved:

  • dmBitsPerPel – This is the bits per pixel or colour depth that is available in the selected graphics mode
  • dmPelsWidth – This is the width of the screen or the x axis.
  • dmPelsHeight – This is the height of the screen or the y axis.

Now to create a function to do this.

Private Declare Function EnumDisplaySettings Lib _
"user32" Alias "EnumDisplaySettingsA" _
(ByVal lpszDeviceName As Long, ByVal iModeNum As Long, _
lpDevMode As Any) As Boolean

'Screen Resolution
Private Const CCDEVICENAME = 32
Private Const CCFORMNAME = 32

Private Type DEVMODE
  dmDeviceName As String * CCDEVICENAME
  dmSpecVersion As Integer
  dmDriverVersion As Integer
  dmSize As Integer
  dmDriverExtra As Integer
  dmFields As Long
  dmOrientation As Integer
  dmPaperSize As Integer
  dmPaperLength As Integer
  dmPaperWidth As Integer
  dmScale As Integer
  dmCopies As Integer
  dmDefaultSource As Integer
  dmPrintQuality As Integer
  dmColor As Integer
  dmDuplex As Integer
  dmYResolution As Integer
  dmTTOption As Integer
  dmCollate As Integer
  dmFormName As String * CCFORMNAME
  dmUnusedPadding As Integer
  dmBitsPerPel As Integer
  dmPelsWidth As Long
  dmPelsHeight As Long
  dmDisplayFlags As Long
  dmDisplayFrequency As Long
End Type

Public Sub EnumDisplay()

Dim lTemp As Long, tDevMode As DEVMODE, lIndex As Long
' Declare variables
lIndex = 0
Do
lTemp = EnumDisplaySettings(0&, lIndex, tDevMode)
' Call the API function with the current index
If lTemp = 0 Then Exit Do
' If the API function returns 0 then no more
' data is availible or an error has occurred.
' As you increase the index on each call
' when there is no more data to enumerate the
' function will return 0

With tDevMode
Debug.Print .dmPelsWidth & " pixels by " _
& .dmPelsHeight & " pixels, Color Mode " _
& .dmBitsPerPel & " bit"
' Print the mode information to the debug
End With

lIndex = lIndex + 1
Loop
End Sub

This function will enumerate all the display modes and display them in the debug window.

The functions here are demonstrated in the EnumDisplayModes demo project.

First, I must emphasise that some of the constants required to do this are undocumented in the VB API viewer, but are listed below and in the sample projects.

To change the screen mode, you must enumerate the possible screen modes, as described earlier, then select the closest match. You then can use the ChangeDisplaySettings API function to actually change the screen resolution:

ChangeDisplaySettings

This API function changes the display settings on the current machine. There are two parameters that are passed which are:

lpDevMode – This acts as a pointer to the DevMode structure that contains information that you want to change. You can set the following parameters of the DevMode structure that will be changed

Meaning Description
dmBitsPerPel This is the number of colours that you want to use or the bits per pixel as I explained earlier on in this article, which can either be 4, 6, 8, 16, 24 or 32 depending on the modes supported.
dmPelsWidth This is the width of the screen in pixels or otherwise known as the x-axis of the screen.
dmPelsHeight This is the height of the screen in pixels or otherwise known as the y-axis of the screen.

This function demonstrates how to change the screen resolution. It enumerates through the available modes, checking each one. When the correct one is found, it is selected. Don’t forget to add the earlier declarations to the ones here:

Private Declare Function ChangeDisplaySettings _
    Lib "user32" _
Alias "ChangeDisplaySettingsA" (lpDevMode As Any, _
ByVal dwflags As Long) As Long

Public Sub ChangeScreenSettings(lWidth As Integer, _
lHeight As Integer, lColors As Integer)

Dim tDevMode As DEVMODE, lTemp As Long, lIndex As Long
' Declare variables
lIndex = 0
Do

lTemp = EnumDisplaySettings(0&, lIndex, tDevMode)
' Call the API function
If lTemp = 0 Then Exit Do
' If there is no more data or an error occurs
' then return 0 and exit do
lIndex = lIndex + 1
' Increase the index to be enumerated
With tDevMode
If .dmPelsWidth = lWidth And .dmPelsHeight = lHeight _
And .dmBitsPerPel = lColors Then
lTemp = ChangeDisplaySettings(tDevMode, CDS_UPDATEREGISTRY)
Exit Do
End If

End With
Loop
' Set the new data
' Change the display type. This depends on the paramter used
' It can either be:
' 0 - Dynamic change if possible
' CDS_UPDATEREGISTRY - Dynamically change if possible
' and if not possible then update registry for change
' on the next boot-up
' CDS_TEST - Test the new settings

Select Case lTemp ' Check for errors
Case DISP_CHANGE_SUCCESSFUL
MsgBox "The display settings change was successful", _
vbInformation

Case DISP_CHANGE_RESTART
MsgBox "The computer must be restarted in order for _
the graphics mode to work", vbQuestion

Case DISP_CHANGE_FAILED
MsgBox "The display driver failed the specified graphics _
mode", vbCritical

Case DISP_CHANGE_BADMODE
MsgBox "The graphics mode is not supported", vbCritical

Case DISP_CHANGE_NOTUPDATED
MsgBox "Unable to write settings to the registry", vbCritical
' NB. Windows NT Only

Case DISP_CHANGE_BADFLAGS
MsgBox "An invalid set of flags was passed in", vbCritical

End Select

End Sub

The functions here are demonstrated in the ChangeDispMode demo project.

Whether you are creating a Visual Basic game, DTP program or a drawing application, harnessing the power of the graphics system is always useful.  If you have any questions about this article, please post a message in our Q and A forum or drop me an email.

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved