Use Windows C # API to install primary monitor

I am trying to use the Windows API to install the primary monitor. It doesn't seem to work - my screen just clicks and nothing happens.

public const int DM_ORIENTATION = 0x00000001; public const int DM_PAPERSIZE = 0x00000002; public const int DM_PAPERLENGTH = 0x00000004; public const int DM_PAPERWIDTH = 0x00000008; public const int DM_SCALE = 0x00000010; public const int DM_POSITION = 0x00000020; public const int DM_NUP = 0x00000040; public const int DM_DISPLAYORIENTATION = 0x00000080; public const int DM_COPIES = 0x00000100; public const int DM_DEFAULTSOURCE = 0x00000200; public const int DM_PRINTQUALITY = 0x00000400; public const int DM_COLOR = 0x00000800; public const int DM_DUPLEX = 0x00001000; public const int DM_YRESOLUTION = 0x00002000; public const int DM_TTOPTION = 0x00004000; public const int DM_COLLATE = 0x00008000; public const int DM_FORMNAME = 0x00010000; public const int DM_LOGPIXELS = 0x00020000; public const int DM_BITSPERPEL = 0x00040000; public const int DM_PELSWIDTH = 0x00080000; public const int DM_PELSHEIGHT = 0x00100000; public const int DM_DISPLAYFLAGS = 0x00200000; public const int DM_DISPLAYFREQUENCY = 0x00400000; public const int DM_ICMMETHOD = 0x00800000; public const int DM_ICMINTENT = 0x01000000; public const int DM_MEDIATYPE = 0x02000000; public const int DM_DITHERTYPE = 0x04000000; public const int DM_PANNINGWIDTH = 0x08000000; public const int DM_PANNINGHEIGHT = 0x10000000; public const int DM_DISPLAYFIXEDOUTPUT = 0x20000000; public const int ENUM_CURRENT_SETTINGS = -1; public const int CDS_UPDATEREGISTRY = 0x01; public const int CDS_TEST = 0x02; public const int CDS_SET_PRIMARY = 0x00000010; public const long DISP_CHANGE_SUCCESSFUL = 0; public const long DISP_CHANGE_RESTART = 1; public const long DISP_CHANGE_FAILED = -1; public const long DISP_CHANGE_BADMODE = -2; public const long DISP_CHANGE_NOTUPDATED = -3; public const long DISP_CHANGE_BADFLAGS = -4; public const long DISP_CHANGE_BADPARAM = -5; public const long DISP_CHANGE_BADDUALVIEW = -6; public static void SetPrimary(Screen screen) { DISPLAY_DEVICE d = new DISPLAY_DEVICE(); DEVMODE dm = new DEVMODE(); d.cb = Marshal.SizeOf(d); uint deviceID = 1; User_32.EnumDisplayDevices(null, deviceID, ref d, 0); // User_32.EnumDisplaySettings(d.DeviceName, 0, ref dm); dm.dmPelsWidth = 2560; dm.dmPelsHeight = 1600; dm.dmPositionX = screen.Bounds.Right; dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; User_32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, CDS_SET_PRIMARY, IntPtr.Zero); } 

I call the method as follows:

 SetPrimary(Screen.AllScreens[1]) 

Any ideas?

+6
c # windows sdk
source share
4 answers

Here is the complete code based on the ADBailey solution:

 public class MonitorChanger { public static void SetAsPrimaryMonitor(uint id) { var device = new DISPLAY_DEVICE(); var deviceMode = new DEVMODE(); device.cb = Marshal.SizeOf(device); NativeMethods.EnumDisplayDevices(null, id, ref device, 0); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode); var offsetx = deviceMode.dmPosition.x; var offsety = deviceMode.dmPosition.y; deviceMode.dmPosition.x = 0; deviceMode.dmPosition.y = 0; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref deviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); device = new DISPLAY_DEVICE(); device.cb = Marshal.SizeOf(device); // Update remaining devices for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++) { if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id) { device.cb = Marshal.SizeOf(device); var otherDeviceMode = new DEVMODE(); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode); otherDeviceMode.dmPosition.x -= offsetx; otherDeviceMode.dmPosition.y -= offsety; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref otherDeviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); } device.cb = Marshal.SizeOf(device); } // Apply settings NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null); } } [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] public struct DEVMODE { public const int CCHDEVICENAME = 32; public const int CCHFORMNAME = 32; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)] [System.Runtime.InteropServices.FieldOffset(0)] public string dmDeviceName; [System.Runtime.InteropServices.FieldOffset(32)] public Int16 dmSpecVersion; [System.Runtime.InteropServices.FieldOffset(34)] public Int16 dmDriverVersion; [System.Runtime.InteropServices.FieldOffset(36)] public Int16 dmSize; [System.Runtime.InteropServices.FieldOffset(38)] public Int16 dmDriverExtra; [System.Runtime.InteropServices.FieldOffset(40)] public UInt32 dmFields; [System.Runtime.InteropServices.FieldOffset(44)] Int16 dmOrientation; [System.Runtime.InteropServices.FieldOffset(46)] Int16 dmPaperSize; [System.Runtime.InteropServices.FieldOffset(48)] Int16 dmPaperLength; [System.Runtime.InteropServices.FieldOffset(50)] Int16 dmPaperWidth; [System.Runtime.InteropServices.FieldOffset(52)] Int16 dmScale; [System.Runtime.InteropServices.FieldOffset(54)] Int16 dmCopies; [System.Runtime.InteropServices.FieldOffset(56)] Int16 dmDefaultSource; [System.Runtime.InteropServices.FieldOffset(58)] Int16 dmPrintQuality; [System.Runtime.InteropServices.FieldOffset(44)] public POINTL dmPosition; [System.Runtime.InteropServices.FieldOffset(52)] public Int32 dmDisplayOrientation; [System.Runtime.InteropServices.FieldOffset(56)] public Int32 dmDisplayFixedOutput; [System.Runtime.InteropServices.FieldOffset(60)] public short dmColor; // See note below! [System.Runtime.InteropServices.FieldOffset(62)] public short dmDuplex; // See note below! [System.Runtime.InteropServices.FieldOffset(64)] public short dmYResolution; [System.Runtime.InteropServices.FieldOffset(66)] public short dmTTOption; [System.Runtime.InteropServices.FieldOffset(68)] public short dmCollate; // See note below! [System.Runtime.InteropServices.FieldOffset(72)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)] public string dmFormName; [System.Runtime.InteropServices.FieldOffset(102)] public Int16 dmLogPixels; [System.Runtime.InteropServices.FieldOffset(104)] public Int32 dmBitsPerPel; [System.Runtime.InteropServices.FieldOffset(108)] public Int32 dmPelsWidth; [System.Runtime.InteropServices.FieldOffset(112)] public Int32 dmPelsHeight; [System.Runtime.InteropServices.FieldOffset(116)] public Int32 dmDisplayFlags; [System.Runtime.InteropServices.FieldOffset(116)] public Int32 dmNup; [System.Runtime.InteropServices.FieldOffset(120)] public Int32 dmDisplayFrequency; } public enum DISP_CHANGE : int { Successful = 0, Restart = 1, Failed = -1, BadMode = -2, NotUpdated = -3, BadFlags = -4, BadParam = -5, BadDualView = -6 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DISPLAY_DEVICE { [MarshalAs(UnmanagedType.U4)] public int cb; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string DeviceName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceString; [MarshalAs(UnmanagedType.U4)] public DisplayDeviceStateFlags StateFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceID; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceKey; } [Flags()] public enum DisplayDeviceStateFlags : int { /// <summary>The device is part of the desktop.</summary> AttachedToDesktop = 0x1, MultiDriver = 0x2, /// <summary>The device is part of the desktop.</summary> PrimaryDevice = 0x4, /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary> MirroringDriver = 0x8, /// <summary>The device is VGA compatible.</summary> VGACompatible = 0x10, /// <summary>The device is removable; it cannot be the primary display.</summary> Removable = 0x20, /// <summary>The device has more display modes than its output devices support.</summary> ModesPruned = 0x8000000, Remote = 0x4000000, Disconnect = 0x2000000, } [Flags()] public enum ChangeDisplaySettingsFlags : uint { CDS_NONE = 0, CDS_UPDATEREGISTRY = 0x00000001, CDS_TEST = 0x00000002, CDS_FULLSCREEN = 0x00000004, CDS_GLOBAL = 0x00000008, CDS_SET_PRIMARY = 0x00000010, CDS_VIDEOPARAMETERS = 0x00000020, CDS_ENABLE_UNSAFE_MODES = 0x00000100, CDS_DISABLE_UNSAFE_MODES = 0x00000200, CDS_RESET = 0x40000000, CDS_RESET_EX = 0x20000000, CDS_NORESET = 0x10000000 } public class NativeMethods { [DllImport("user32.dll")] public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll")] // A signature for ChangeDisplaySettingsEx with a DEVMODE struct as the second parameter won't allow you to pass in IntPtr.Zero, so create an overload public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll")] public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags); [DllImport("user32.dll")] public static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode); } [StructLayout(LayoutKind.Sequential)] public struct POINTL { public int x; public int y; } 
+5
source share

I ran into the same problem, both with C #, and after I advised trying it in C ++. In the end, I found that what is not mentioned in the Microsoft documentation is that the request to install the main monitor will be ignored (but with a successful operation!), Unless you also set the monitor position (0, 0) to DEVMODE structure. Of course, this means that you also need to shift the positions of other monitors so that they stay in one place compared to the new main monitor. In the documentation ( http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx ) call ChangeDisplaySettingsEx for each monitor with the CDS_NORESET flag, and then make the final call with all null.

The following code worked for me:

  public static void SetAsPrimaryMonitor(uint id) { var device = new DISPLAY_DEVICE(); var deviceMode = new DEVMODE(); device.cb = Marshal.SizeOf(device); NativeMethods.EnumDisplayDevices(null, id, ref device, 0); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode); var offsetx = deviceMode.dmPosition.x; var offsety = deviceMode.dmPosition.y; deviceMode.dmPosition.x = 0; deviceMode.dmPosition.y = 0; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref deviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); device = new DISPLAY_DEVICE(); device.cb = Marshal.SizeOf(device); // Update remaining devices for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++) { if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id) { device.cb = Marshal.SizeOf(device); var otherDeviceMode = new DEVMODE(); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode); otherDeviceMode.dmPosition.x -= offsetx; otherDeviceMode.dmPosition.y -= offsety; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref otherDeviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); } device.cb = Marshal.SizeOf(device); } // Apply settings NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null); } 

Note that the signature for ChangeDisplaySettingsEx with the DEVMODE construct as the second parameter will obviously not allow you to go into IntPtr.Zero. Create yourself two different signatures for the same external call, i.e.

  [DllImport("user32.dll")] public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll")] public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); 
+4
source share

I cannot help you with winapi, but if you are using an Nvidia card, you can take a look at the NVcontrolPanel Api Documentation Then you can make secondary output your primary using rundll32.exe NvCpl.dll,dtcfg primary 2 Hope this helps you.

+3
source share

According to the documentation for ChangeDisplaySettingsEx , the dmSize member should be initialized in bytes in the DEVMODE structure. "In addition, the EnumDisplaySettings documentation says:" Before calling EnumDisplaySettings, set the dmSize member to sizeof (DEVMODE) and set the dmDriverExtra member to specify the size, in bytes, of the extra space available for receiving private driver data. "I do not see this in the code example asked in the question; this is one of the reasons why this might be unsuccessful.

In addition, you may have errors in the definitions of the DEVMODE and DISPLAY_DEVICE structures that were not included in the question. Roger Lipscomb's suggestion to get him working with C / C ++ is a great way to eliminate this problem.

Finally, check the return value from ChangeDisplaySettingsEx and see if this gives an idea of ​​why this might fail.

+3
source share

All Articles