Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

.NET Wrapper for ChangeDisplaySettingsEX

2.86/5 (3 votes)
6 Jul 2009CPOL2 min read 51.5K   3.1K  
ChangeDisplaySettingsEx
Display Settings Tester

Introduction

While creating a program that would allow me to quickly change my display settings, I discovered that there were not many working examples for the .NET environment and none showed the whole picture of changing resolutions and primary displays as well as attaching and detaching monitors.

The UpdateSettings function is capable of setting the primary display, attaching and detaching, and setting the display properties Size, BitsPerPixel, Frequency.

Background

I am constantly changing the display settings on my dual monitor computer depending on what I am doing. For example, when I am using Visual Studio I like to have both monitors running at 1280 by 1024, but when I am web browsing I will set them to 1024 by 768. Then there are the sim/adventure games where the edge of the screen is used to scroll the world. These do not function too well if you have a second monitor attached. So it's another display setting change to drop the second monitor.

Using the Code

Display_Settings can be added to any form. It contains properties that allow you to give it comboboxes and panels and trackbars to populate and control. This means you need to only call the UpdateSettings on a Apply button. All control properties are handled to ensure no incorrect settings are applied. Display_Settings also provides events that allow you to control your own controls.

VB.NET
Private Sub btnApply_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnApply.Click
    Me.Display_Settings1.UpdateSettings()
End Sub    

The UpdateSettings function also allows you to update stored settings by passing it an array of the Display_Settings.Display class. The Display_Settings.Display class is Serializable and inherits from Kim Major's ContractBase(of T) class. This allows for easy Serialization. Big thanks to Kim Major for this class.

The UpdateSettings function starts by setting the primary display. This is achieved by moving the current primary display away from position 0,0 and moving the new primary display to position 0,0.

It then loops through each display device. If the display is to be detached, it will move it to position 0,0 and set its size to 0,0. If the display is attached, it will set it to its new settings. This also has the effect of attaching any displays not previously attached.

Finally we loop through all the display devices again and apply the settings.

UpdateSettings Function

VB.NET
Public Function UpdateSettings(ByVal Displays As Display()) _
	As WinAPI.DisplaySetting_Results
        If Not Me.PrimaryDisplayID = Me.PrimaryDisplayRegistryID Then
            SetPrimaryDisplay(Me.m_Displays(Me.PrimaryDisplayRegistryID).DeviceName, _
            	Me.m_Displays(Me.PrimaryDisplayID).DeviceName)
        End If
        For Each disp As Display In Displays
            If Not disp.Attached Then
                Dim dm As New WinAPI.DEVMODE
                dm.dmDeviceName = New [String](New Char(31) {})
                dm.dmFormName = New [String](New Char(31) {})
                dm.dmSize = CShort(Marshal.SizeOf(dm))
                dm.dmFields = WinAPI.DEVMODE_Flags.DM_POSITION Or _
                	WinAPI.DEVMODE_Flags.DM_PELSWIDTH Or WinAPI.DEVMODE_Flags.DM_PELSHEIGHT
                dm.dmPelsWidth = 0
                dm.dmPelsHeight = 0
                dm.dmPosition.x = 0
                dm.dmPosition.y = 0
                Dim Result As WinAPI.DisplaySetting_Results = _
		WinAPI.ChangeDisplaySettingsEx_
                	(disp.DeviceName, dm, Nothing, WinAPI.DeviceFlags.CDS_UPDATEREGISTRY _
                	Or WinAPI.DeviceFlags.CDS_NORESET, 0)
            Else
                Dim dm As New WinAPI.DEVMODE
                dm.dmDeviceName = New [String](New Char(31) {})
                dm.dmFormName = New [String](New Char(31) {})
                dm.dmSize = CShort(Marshal.SizeOf(dm))
                dm.dmFields = WinAPI.DEVMODE_Flags.DM_POSITION Or _
                	WinAPI.DEVMODE_Flags.DM_PELSWIDTH Or _
		WinAPI.DEVMODE_Flags.DM_PELSHEIGHT _
                	Or WinAPI.DEVMODE_Flags.DM_DISPLAYFLAGS _
                	Or WinAPI.DEVMODE_Flags.DM_BITSPERPEL _
                	Or WinAPI.DEVMODE_Flags.DM_DISPLAYFREQUENCY
                dm.dmPelsWidth = disp.Size.Width
                dm.dmPelsHeight = disp.Size.Height
                dm.dmPosition.x = disp.Location.X
                dm.dmPosition.y = disp.Location.Y
                dm.dmBitsPerPel = disp.BitsPerPixel
                dm.dmDisplayFrequency = disp.Frequency
                Dim Result As WinAPI.DisplaySetting_Results = _
                	WinAPI.ChangeDisplaySettingsEx(disp.DeviceName, dm, _
                	Nothing, WinAPI.DeviceFlags.CDS_SET_PRIMARY _
                	Or WinAPI.DeviceFlags.CDS_UPDATEREGISTRY _
                	Or WinAPI.DeviceFlags.CDS_NORESET, 0)

            End If
        Next
        For i As Integer = Displays.Length - 1 To 0 Step -1
            Dim dm1 As New WinAPI.DEVMODE
            dm1.dmDeviceName = New [String](New Char(31) {})
            dm1.dmFormName = New [String](New Char(31) {})
            dm1.dmSize = CShort(Marshal.SizeOf(dm1))
            Dim lStatus As WinAPI.DisplaySetting_Results = _
            	WinAPI.ChangeDisplaySettingsEx(Me.m_Displays(i).DeviceName, _
            		dm1, Nothing, WinAPI.DeviceFlags.CDS_UPDATEREGISTRY, Nothing)
            WinAPI.OutputDebugString(lStatus.ToString & vbCrLf)
        Next
        Me.InitializeDisplays()
    End Function  

SetPrimaryDisplay Function

VB.NET
Public Sub SetPrimaryDisplay_
	(ByVal OldPrimary As String, ByVal NewPrimary As String)
        Dim Result As WinAPI.DisplaySetting_Results = 0

        Dim dm1 As WinAPI.DEVMODE = NewDevMode()
        WinAPI.EnumDisplaySettings(NewPrimary, _
		WinAPI.DEVMODE_SETTINGS.ENUM_REGISTRY_SETTINGS, dm1)
        Dim dm3 As WinAPI.DEVMODE = NewDevMode()
        dm3.dmFields = WinAPI.DEVMODE_Flags.DM_POSITION
        dm3.dmPosition.x = dm1.dmPelsWidth
        dm3.dmPosition.y = 0
        Result = WinAPI.ChangeDisplaySettingsEx(OldPrimary, dm3, _
        	Nothing, WinAPI.DeviceFlags.CDS_UPDATEREGISTRY _
		Or WinAPI.DeviceFlags.CDS_NORESET, 0)
        Console.WriteLine(Result.ToString)

        Dim dm2 As WinAPI.DEVMODE = NewDevMode()
        WinAPI.EnumDisplaySettings(NewPrimary, _
		WinAPI.DEVMODE_SETTINGS.ENUM_REGISTRY_SETTINGS, dm2)
        Dim dm4 As WinAPI.DEVMODE = NewDevMode()
        dm4.dmFields = WinAPI.DEVMODE_Flags.DM_POSITION
        dm4.dmPosition.x = 0
        dm4.dmPosition.y = 0
        Result = WinAPI.ChangeDisplaySettingsEx(NewPrimary, dm4, Nothing, _
        	WinAPI.DeviceFlags.CDS_SET_PRIMARY Or WinAPI.DeviceFlags.CDS_UPDATEREGISTRY _
        	Or WinAPI.DeviceFlags.CDS_NORESET, 0)
        Console.WriteLine(Result.ToString)

        Dim dm5 As WinAPI.DEVMODE = NewDevMode()
        Result = WinAPI.ChangeDisplaySettingsEx(OldPrimary, dm5, _
        	Nothing, WinAPI.DeviceFlags.CDS_UPDATEREGISTRY, Nothing)
        Console.WriteLine(Result.ToString)
        Dim dm6 As WinAPI.DEVMODE = NewDevMode()
        Result = WinAPI.ChangeDisplaySettingsEx(NewPrimary, dm6, Nothing, _
        	WinAPI.DeviceFlags.CDS_SET_PRIMARY Or WinAPI.DeviceFlags.CDS_UPDATEREGISTRY, 0)
        Console.WriteLine(Result.ToString)

        Console.WriteLine(Result.ToString)
    End Sub

Points of Interest

Always ensure your displays have a common edge. If the screens overlap or there is a gap, you can get some really strange effects, e.g. you mouse pointer does not point to where the mouse point is. I had to use the keyboard a couple of times to reset my display settings.

ChangeDisplaySettingsEX recommends that to apply the settings, you should use ChangeDisplaySettingsEX(nothing, nothing, nothing, 0, nothing). This did not work for me. I had to call ChangeDisplaySettingsEX for each device name with an empty DEVMODE structure and the flag CDS_UPDATEREGISTRY.

History

  • 6th July, 2009: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)