Click here to Skip to main content
15,890,512 members
Articles / Programming Languages / C#

Set Primary Display (ChangeDisplaySettingsEx)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
11 Aug 2009CPOL 65.3K   2.8K   18   6
Simplified code for setting the primary display on a multi-monitor PC.

Image 1

Introduction

I've seen plenty of "complicated" code for setting the "primary" display in a multiple display PC environment, but never a "simple" C# version. (This code is based off plenty of samples I've seen on the web.)

Background

This code originated out of the need to pop applications to multiple monitors during an automated start-up script (i.e., set a designated monitor as primary, start apps, then revert back to original monitor).

Using the code

The code is left raw for addition of "bells and whistles".

C#
//manual gather - NewPrimary name ----------------------------------
WinApi.DISPLAY_DEVICE ddOne = new WinApi.DISPLAY_DEVICE();

ddOne.cb = Marshal.SizeOf(ddOne);
deviceID = 1;
WinApi.User_32.EnumDisplayDevices(null, deviceID, ref ddOne, 0);
string NewPrimary = ddOne.DeviceName;

WinApi.DEVMODE ndm6 = NewDevMode();
result = (WinApi.DisplaySetting_Results)WinApi.User_32.ChangeDisplaySettingsEx(NewPrimary, 
          ref ndm6, (IntPtr)null, (int)WinApi.DeviceFlags.CDS_SET_PRIMARY | 
          (int)WinApi.DeviceFlags.CDS_UPDATEREGISTRY, IntPtr.Zero);
Console.WriteLine("Action 3.2 result:" + result.ToString());

License

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


Written By
Systems Engineer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionWorking VB.Net "Conversion" Pin
LostIt127823-Jan-13 16:55
LostIt127823-Jan-13 16:55 
GeneralRe: Working VB.Net "Conversion" Pin
LostIt127824-Feb-13 7:59
LostIt127824-Feb-13 7:59 
I've improved my code since my last post. The new version keeps monitor positions.



VB
Imports System.Runtime.InteropServices

Class clsPrimaryScreen
    Public Shared Function NewDevMode() As WinAPI.DEVMODE
        Dim dm As New WinAPI.DEVMODE()
        dm.dmDeviceName = New [String](New Char(30) {})
        dm.dmFormName = New [String](New Char(30) {})
        dm.dmSize = CUShort(Marshal.SizeOf(dm))
        Return dm
    End Function
    Public Shared Function SetPrimary(Optional ByVal oNewPrimary As Screen = Nothing) As Boolean
        ' Only tested on dual monitors but may (should) work on more.
        Dim result As WinAPI.DisplaySetting_Results = 0
        Dim OldPrimary As String = Screen.PrimaryScreen.DeviceName
        Dim NewPrimary As String = ""
        If oNewPrimary Is Nothing Then
            For Each oScreen As Screen In Screen.AllScreens
                If Not oScreen.Primary Then
                    oNewPrimary = oScreen
                    Exit For
                End If
            Next
        End If
        If Not oNewPrimary Is Nothing Then
            NewPrimary = oNewPrimary.DeviceName
        ElseIf oNewPrimary.Primary Then
            Return True
        Else
            Return False
        End If

        ' Offset. All monitors must change position based on these offsets to maintain relative position to each other.
        Dim iOffsetX As Integer = 0 - oNewPrimary.WorkingArea.Location.X
        Dim iOffsetY As Integer = 0 - oNewPrimary.WorkingArea.Location.Y

        ' Get settings needed for new monitor positions after primary change.
        Dim lSettings As New List(Of clsScreenSettings)
        Dim oSetting As clsScreenSettings
        For Each oScr As Screen In Screen.AllScreens
            oSetting = New clsScreenSettings
            oSetting.DeviceName = oScr.DeviceName
            oSetting.X = oScr.WorkingArea.Location.X + iOffsetX
            oSetting.Y = oScr.WorkingArea.Location.Y + iOffsetY
            lSettings.Add(oSetting)
        Next

        Dim oDevMode As DEVMODE
        ' Set new primary position and primary flag
        For Each oSetting In lSettings
            If oSetting.DeviceName <> NewPrimary Then Continue For
            Dim oDevFlags As DeviceFlags
            oDevFlags = CType(CInt(WinAPI.DeviceFlags.CDS_SET_PRIMARY) Or CInt(WinAPI.DeviceFlags.CDS_UPDATEREGISTRY) Or CInt(WinAPI.DeviceFlags.CDS_NORESET), DeviceFlags)
            oDevMode = NewDevMode()
            oDevMode.dmFields = WinAPI.DEVMODE_Flags.DM_POSITION
            oDevMode.dmPosition.x = oSetting.X
            oDevMode.dmPosition.y = oSetting.Y
            result = DirectCast(WinAPI.ChangeDisplaySettingsEx(oSetting.DeviceName, oDevMode, 0, oDevFlags, 0), WinAPI.DisplaySetting_Results)

            ' Apply Changes. If we don't apply changes now the screens' positions will be off.
            oDevMode = NewDevMode()
            result = DirectCast(WinAPI.ChangeDisplaySettingsEx(OldPrimary, oDevMode, 0, CType(WinAPI.DeviceFlags.CDS_RESET, DeviceFlags), 0), WinAPI.DisplaySetting_Results)
            If result <> DisplaySetting_Results.DISP_CHANGE_SUCCESSFUL Then Return False
            Exit For
        Next

        ' Set the posotion of all non-primary screens.
        For Each oSetting In lSettings
            If oSetting.DeviceName = NewPrimary Then Continue For
            Dim oDevFlags As DeviceFlags
            oDevFlags = CType(CInt(WinAPI.DeviceFlags.CDS_UPDATEREGISTRY) Or CInt(WinAPI.DeviceFlags.CDS_NORESET), DeviceFlags)
            oDevMode = NewDevMode()
            oDevMode.dmFields = WinAPI.DEVMODE_Flags.DM_POSITION
            oDevMode.dmPosition.x = oSetting.X
            oDevMode.dmPosition.y = oSetting.Y
            result = DirectCast(WinAPI.ChangeDisplaySettingsEx(oSetting.DeviceName, oDevMode, 0, oDevFlags, 0), WinAPI.DisplaySetting_Results)
        Next

        ' Apply Changes
        oDevMode = NewDevMode()
        result = DirectCast(WinAPI.ChangeDisplaySettingsEx(OldPrimary, oDevMode, 0, CType(WinAPI.DeviceFlags.CDS_RESET, DeviceFlags), 0), WinAPI.DisplaySetting_Results)
        If result <> DisplaySetting_Results.DISP_CHANGE_SUCCESSFUL Then Return False

        Return True
    End Function
End Class
Class clsScreenSettings
    Public X As Integer
    Public Y As Integer
    Public DeviceName As String
End Class


modified 4-Mar-13 1:53am.

GeneralDoes not work for me. Pin
Bill Langlais2-Nov-09 13:02
Bill Langlais2-Nov-09 13:02 
GeneralManually set monitor\display name Pin
beyonder42211-Aug-09 5:48
beyonder42211-Aug-09 5:48 
GeneralRe: Manually set monitor\display name Pin
The_Mega_ZZTer11-Aug-09 6:51
The_Mega_ZZTer11-Aug-09 6:51 
GeneralRe: Manually set monitor\display name Pin
dalek925-Aug-09 2:23
dalek925-Aug-09 2:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.