Free Web Hosting Provider - Web Hosting - E-commerce - High Speed Internet - Free Web Page
Search the Web

Windows 2000 Graphics API Black Book
Home | Introduction | Table of Contents | Updates | New Stuff | Links | About the Authors | Ordering
 

Enumerating and Changing the Display Settings
 

Although it is not common for an application to manipulate the end-user’s display settings, there may be situations where this is warranted.  For example, if your application works best under a specific resolution, you may want to offer your consumers the ability to quickly switch to this resolution from within the software.  In other cases, for example when displaying natural images, you many want to offer a feature that allows the color-depth to be increased to the maximum value that the current monitor can support.  Or, if you’re creating a GDI-based game, you may want to automatically switch the end-user’s display settings from a high-resolution high-color mode, to a low-resolution low-color mode, for increased performance.
 

WARNING:  It is generally bad practice to automatically adjust the display settings without warning the user in some fashion.

Enumerating the Available Display Settings

Before you can switch to a specific display setting, you need to determine which settings are supported by the video device driver.  To this end, Windows presents the EnumDisplaySettings function: 

 

BOOL EnumDisplaySettings(

    IN LPCTSTR lpszDeviceName,       // a string that specifies the display device

    IN DWORD iModeNum,               // graphics mode index to query

    OUT LPDEVMODE lpDevMode          // pointer to a DEVMODE structure  

   );

 

The lpszDeviceName parameter is assigned the name of the display device whose settings are to be retrieved.  Typically, this value is specified as NULL, indicating that the application’s current display device should be queried.  In fact, on systems running Windows 95, this parameter must be set to NULL.  On Windows 98/Me/NT/2000-based systems, the lpszDeviceName parameter can either be set to NULL, or the literal “\\.\Display#”, where # is a number ranging from one to three for systems running Windows NT, or from one to the number of display devices for systems running Windows 98/Me/2000.  The iMode parameter indicates the display mode to be queried, and when incremented to a value greater than the available display modes, the function will return false.   If successful, the EnumDisplaySettings function returns true, and the retrieved information is stored in the DEVMODE structure specified via the lpDevMode parameter.
 

The DEVMODE type is a special structure whose 37 data members serve to hold information about a DEVice’s MODEs (settings).  This structure is primarily used for printer settings, so many of its data members are irrelevant when working with a video display device.  For most situations, you only need concern yourself with all or only some of the five data members that are exclusive to video display devices.  These five data members are explained in Table 1.13.
 

Table 1.13 The DEVMODE data members that are exclusive to video display device drivers

Data Member  Information Yielded
dmBitsPerPel      

The number of bits that the display driver uses to represent a pixel.

dmPelsWidth      

The number of visible pixels in the horizontal direction (width).

dmPelsHeight     

The number of visible pixels in the vertical direction (height).

dmDisplayFlags 

Indicates if the current display mode does not support color (DM_GRAYSCALE) or is interlaced (DM_INTERLACED).

dmDisplayFrequency        

Indicated the vertical refresh rate in Hz.  If this value is set to 0 or 1, the driver’s default refresh rate is being used.

dmPosition

Indicates the position of the display device relative to the desktop.  This data member is only valid for systems running Windows 98/2000 usiing a multiple monitor setup.

  

When used in an iterative fashion, the EnumDisplaySettings function can yield information about all of the available display settings.  That is, unlike other enumeration-type functions, there is no parameter that accepts a pointer to a callback function.  Instead, the EnumDisplaySettings function is called repetitively, each time with an incremented iMode parameter, until the function returns false:

 

DEVMODE dm;

memset(&dm, 0, sizeof(DEVMODE));

int current_mode = 0;

 

while (EnumDisplaySettings(NULL, current_mode++, &dm))

{

   //

   // examine the relevant data members

   // of "dm" and act accordingly...

   //

}

 

Changing The Current Display Settings
Once you have determined the capabilities of the video display driver, you can switch to one of the available graphic modes via the ChangeDisplaySettings function:

 

LONG ChangeDisplaySettings(

    IN LPDEVMODE lpDevMode,   // pointer to an initialized DEVMODE structure

    IN DWORD dwflags          // flags indicating the valid DEVMODE data members

   );

 

Because this function accepts a pointer to a DEVMODE structure as its first parameter, it is used almost exclusively in conjunction with the EnumDisplaySettings function.  However, before you pass the address of the initialized DEVMODE structure as the lpDevMode parameter, you need to convey to the ChangeDisplaySettings functions which data members of the DEVMODE structure are valid.  This is accomplished by assigning the appropriate flags to the structure’s dmFields data member.  This data member can be assigned a combination of any of the values listed in Table 1.14.

Table 1.14 Flags that can be assigned to the dmFields data member for use with the ChangeDisplaySettings function

Flag     Interpretation
DM_BITSPERPEL              

The dmBitsPerPel data member contains valid information.

DM_PELSWIDTH                               

The dmPelsWidth data member contains valid information.

DM_PELSHEIGHT             

The dmPelsHeight data member contains valid information.

DM_DISPLAYFLAGS          

The dmDisplayFlags data member contains valid information.

DM_DISPLAYFREQENCY

The dmDisplayFrequency data member contains valid information.

DM_POSITION    

The dmPosition data member contains valid information.

 

WARNING:  While you are free to manually initialize the relevant DEVMODE data members and  then pass the address of this DEVMODE structure as the lpDevMode parameter, the specified settings may not be supported by the video device driver.  It is best to always use the ChangeDisplaySettings function in combination with the EnumDisplaySettings function.

 

The dwflags parameter of the ChangeDisplaySettings function is used to specify the nature of the change.  The possible values for this parameter are listed in Table 1.15.

Table 1.15 Values that can bas specified as the dwflags parameter of the ChangeDisplaySettings function

Flag     Interpretation
CDS_UPDATEREGISTRY

The display device settings will be dynamically changed to the specified settings, and the new settings will be stored in the registry for the current user.

CDS_GLOBAL    

Modifies the CDS_UPDATEREGISTRY flag so that the new settings will be stored in the registry for all users, not just the current user.

CDS_TEST          

The display device is tested for support of the specified settings.

CDS_RESET       

The display device will be dynamically changed to the specified settings, even if no change is required (i.e., the specified settings are identical to the current settings). 

CDS_NORESET 

Modifies the CDS_UPDATEREGISTRY flag so that the new settings will be stored in the registry, but no dynamic changes to the current settings will be made.

CDS_SETPRIMARY           

For systems with multiple display devices, use of this flag instructs the ChangeDisplaySettings function to set the specified device as the primary device.

CDS_FULSCREEN           

For applications that are switching to or from full-screen mode, use of this flag instructs the system not to reposition other windows.

0                     The display device settings will be dynamically changed to the specified settings.

 

WARNING:  For systems running Windows NT, the CDS_UPDATEREGISTRY flag is required for the Windows Shell to properly reposition the Taskbar.

TIP:  Even when used in conjunction with the EnumDisplaySettings function, it is good practice to first call the ChangeDisplaySettings function with the CDS_TEST flag to guarantee that the graphic mode is supported.

The return value of the ChangeDisplaySettings function indicates the success, failure,  reason of failure, or requirements of the change.  This value can take on one of the constants listed in Table 1.16.

Table 1.16 Possible return values of the ChangeDisplaySettings function

Identifier        

Value

Interpretation
DISP_CHANGE_SUCCESSFUL      0

The graphic mode has been successfully changed.

DISP_CHANGE_RESTART               1

The new settings require a reboot before they can take effect.

DISP_CHANGE_FAILED   -1

An attempt to change to the new graphic mode has failed.

DISP_CHANGE_BADMODE             -2 The specified graphic mode is unsupported.
DISP_CHANGE_NOTUPDATED      -3

The new graphic mode has been successfully changed, but an attempt to change the registry has failed (Windows NT/2000 only).

DISP_CHANGE_BADFLAGS            -4

One or more of the flags passed as the dwFlags parameter is incorrect.

DISP_CHANGE_BADPARAM            -5

One or more of the specified parameters is incorrect.

 

Although the ChangeDisplaySettings function has a multitude of accompanying constants as listed in Tables 1.13, 1.14, and 1.15, using this function isn't as complicated at it may seem.  Typically, you pass the ChangeDisplaySettings function the DEVMODE structure that has been initialized by the EnumDisplaySettings function along with the CDS_TEST flag as the dwflags parameter.  This will ensure that the change in settings can indeed be carried out.  If successful, you call the ChangeDisplaySettings function again, this time with the CDS_UPDATEREGISTRY flag as the dwflags parameter.
 
The following example functions demonstrate how to use the ChangeDisplaySettings function to switch to a specific resolution (ChangeResolution) and color-depth (ChangeColorDepth):

 

//

// EXAMPLE #1: Changing the resolution

// 

int ChangeResolution(LPSIZE lpSize)

{

   DEVMODE dm;

   memset(&dm, 0, sizeof(DEVMODE));

 

   int current_mode = 0;

   int result = DISP_CHANGE_BADMODE;

 

   // enumerate the available graphic modes

   while (EnumDisplaySettings(NULL, current_mode++, &dm))

   {              

      // when the desired settings are met...

      if (dm.dmPelsWidth == static_cast<DWORD>(lpSize->cx) &&

          dm.dmPelsHeight == static_cast<DWORD>(lpSize->cy))

      {

         // tell the function which settings to change

         dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

 

         // test to ensure that a change will succeed

         result = ChangeDisplaySettings(&dm, CDS_TEST);

 

         // if successful...

         if (result == DISP_CHANGE_SUCCESSFUL)

         {

             // change to the new graphic mode

            return ChangeDisplaySettings(

               &dm, CDS_UPDATEREGISTRY

               );

         }

      }

   }

   // otherwise, return the result

   return result;

}

 

  

//

// EXAMPLE #2: Changing the color-depth

// 

int ChangeColorDepth(WORD bits_per_pixel)

{

   DEVMODE dm;

   memset(&dm, 0, sizeof(DEVMODE));

 

   int current_mode = 0;

   int result = DISP_CHANGE_BADMODE;

 

   // enumerate the available graphic modes

   while (EnumDisplaySettings(NULL, current_mode++, &dm))

   {              

      // when the desired setting is met...

      if (dm.dmBitsPerPel == bits_per_pixel)

      {

         // tell the function which setting to change

         dm.dmFields = DM_BITSPERPEL;

 

         // test to ensure that a change will succeed

         result = ChangeDisplaySettings(&dm, CDS_TEST);

 

         // if successful...

         if (result == DISP_CHANGE_SUCCESSFUL)

         {

            // change to the new graphic mode

            return ChangeDisplaySettings(

               &dm, CDS_UPDATEREGISTRY

                );

         }

      }

   }

   // otherwise, return the result

   return result;

}

 

In most cases, the return value will indicate success (DISP_CHANGE_SUCCESS).  For some configurations, the change may require that the system be rebooted (DISP_CHANGE_RESTART).  If access restrictions apply, the DISP_CHANGE_NOTUPDATED identifier is returned.  Using this typical scheme, unless your manipulate the initialized DEVMODE structure, rarely will you need deal with any other return values.

 

Copyright © 2001 Damon Chandler and Michael Fötsch