Introduction
I have always had a fascination with screen display settings. Well, I like to play with a computer’s display and all the options in code. It is wonderful what .NET and Windows enable you to do. If you revisit some of my older articles, you would see articles that includes the taskbar settings, desktop icons, screen savers, and display settings. Today, you will learn how to create a .NET application that enables you to rotate any one of your display screens and to reset them back.
Practical
You will create a .NET Windows Forms application in C# or in Visual Basic with four buttons. Three buttons will be used for the three different displays. The fourth button will be used to Reset the displays back to their original values. Let us jump straight to the code!
Add a class to your project, and name it APIStuff. This class will be responsible for all the Windows APIs aiding you in setting display settings. Because you will be dealing with the system API, you need to import the correct Namespaces. Do this now.
C#
using System; using System.Runtime.InteropServices;
VB.NET
Imports System.Runtime.InteropServices
Now, add the following API methods.
C#
[DllImport("user32.dll")] internal static extern DISP_CHANGE ChangeDisplaySettingsEx (string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, DisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll")] internal static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags); [DllImport("user32.dll", CharSet = CharSet.Ansi)] internal static extern int EnumDisplaySettings (string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);
VB.NET
<DllImport("user32.dll")> Friend Shared Function ChangeDisplaySettingsEx(ByVal _ lpszDeviceName As String, ByRef lpDevMode As DEVMODE, _ ByVal hwnd As IntPtr, ByVal dwflags As DisplaySettingsFlags, _ ByVal lParam As IntPtr) As DISP_CHANGE End Function <DllImport("user32.dll")> Friend Shared Function EnumDisplayDevices(ByVal lpDevice As _ String, ByVal iDevNum As UInteger, ByRef lpDisplayDevice _ As DISPLAY_DEVICE, ByVal dwFlags As UInteger) As Boolean End Function <DllImport("user32.dll", CharSet:=CharSet.Ansi)> Friend Shared Function EnumDisplaySettings(ByVal lpszDeviceName _ As String, ByVal iModeNum As Integer, ByRef lpDevMode _ As DEVMODE) As Integer End Function
ChangeDisplaySettingsEx changes the settings of the specified display to the specified graphics mode. EnumDisplayDevices obtains information about the display devices. EnumDisplaySettings retrieves information of the graphics modes of a display device.
Add the Constants and Structures that work with the preceding API functions.
C#
public const int DMDO_DEFAULT = 0; public const int DMDO_90 = 1; public const int DMDO_180 = 2; public const int DMDO_270 = 3; public const int ENUM_CURRENT_SETTINGS = -1; [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] internal struct DEVMODE { public const int CCHDEVICENAME = 32; public const int CCHFORMNAME = 32; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)] [FieldOffset(0)] public string dmDeviceName; [FieldOffset(32)] public Int16 dmSpecVersion; [FieldOffset(34)] public Int16 dmDriverVersion; [FieldOffset(36)] public Int16 dmSize; [FieldOffset(38)] public Int16 dmDriverExtra; [FieldOffset(40)] public DM dmFields; [FieldOffset(44)] Int16 dmOrientation; [FieldOffset(46)] Int16 dmPaperSize; [FieldOffset(48)] Int16 dmPaperLength; [FieldOffset(50)] Int16 dmPaperWidth; [FieldOffset(52)] Int16 dmScale; [FieldOffset(54)] Int16 dmCopies; [FieldOffset(56)] Int16 dmDefaultSource; [FieldOffset(58)] Int16 dmPrintQuality; [FieldOffset(44)] public POINTL dmPosition; [FieldOffset(52)] public Int32 dmDisplayOrientation; [FieldOffset(56)] public Int32 dmDisplayFixedOutput; [FieldOffset(60)] public short dmColor; [FieldOffset(62)] public short dmDuplex; [FieldOffset(64)] public short dmYResolution; [FieldOffset(66)] public short dmTTOption; [FieldOffset(68)] public short dmCollate; [FieldOffset(72)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)] public string dmFormName; [FieldOffset(102)] public Int16 dmLogPixels; [FieldOffset(104)] public Int32 dmBitsPerPel; [FieldOffset(108)] public Int32 dmPelsWidth; [FieldOffset(112)] public Int32 dmPelsHeight; [FieldOffset(116)] public Int32 dmDisplayFlags; [FieldOffset(116)] public Int32 dmNup; [FieldOffset(120)] public Int32 dmDisplayFrequency; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal 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; } [StructLayout(LayoutKind.Sequential)] internal struct POINTL { long x; long y; }
VB.NET
Public Const DMDO_DEFAULT As Integer = 0 Public Const DMDO_90 As Integer = 1 Public Const DMDO_180 As Integer = 2 Public Const DMDO_270 As Integer = 3 Public Const ENUM_CURRENT_SETTINGS As Integer = -1 <StructLayout(LayoutKind.Explicit, CharSet:=CharSet.Ansi)> Friend Structure DEVMODE Public Const CCHDEVICENAME As Integer = 32 Public Const CCHFORMNAME As Integer = 32 <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHDEVICENAME)> <FieldOffset(0)> Public dmDeviceName As String <FieldOffset(32)> Public dmSpecVersion As Int16 <FieldOffset(34)> Public dmDriverVersion As Int16 <FieldOffset(36)> Public dmSize As Int16 <FieldOffset(38)> Public dmDriverExtra As Int16 <FieldOffset(40)> Public dmFields As DM <FieldOffset(44)> Private dmOrientation As Int16 <FieldOffset(46)> Private dmPaperSize As Int16 <FieldOffset(48)> Private dmPaperLength As Int16 <FieldOffset(50)> Private dmPaperWidth As Int16 <FieldOffset(52)> Private dmScale As Int16 <FieldOffset(54)> Private dmCopies As Int16 <FieldOffset(56)> Private dmDefaultSource As Int16 <FieldOffset(58)> Private dmPrintQuality As Int16 <FieldOffset(44)> Public dmPosition As POINTL <FieldOffset(52)> Public dmDisplayOrientation As Int32 <FieldOffset(56)> Public dmDisplayFixedOutput As Int32 <FieldOffset(60)> Public dmColor As Short <FieldOffset(62)> Public dmDuplex As Short <FieldOffset(64)> Public dmYResolution As Short <FieldOffset(66)> Public dmTTOption As Short <FieldOffset(68)> Public dmCollate As Short <FieldOffset(72)> <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHFORMNAME)> Public dmFormName As String <FieldOffset(102)> Public dmLogPixels As Int16 <FieldOffset(104)> Public dmBitsPerPel As Int32 <FieldOffset(108)> Public dmPelsWidth As Int32 <FieldOffset(112)> Public dmPelsHeight As Int32 <FieldOffset(116)> Public dmDisplayFlags As Int32 <FieldOffset(116)> Public dmNup As Int32 <FieldOffset(120)> Public dmDisplayFrequency As Int32 End Structure <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> Friend Structure DISPLAY_DEVICE <MarshalAs(UnmanagedType.U4)> Public cb As Integer <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Public DeviceName As String <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> Public DeviceString As String <MarshalAs(UnmanagedType.U4)> Public StateFlags As DisplayDeviceStateFlags <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> Public DeviceID As String <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> Public DeviceKey As String End Structure <StructLayout(LayoutKind.Sequential)> Friend Structure POINTL Private x As Long Private y As Long End Structure
The DEVMODE structure contains information about the environment of a display device. DISPLAY_DEVICE receives information about the given display device. POINTL simply contains the coordinates of a point. Add the next few Enumerations.
C#
internal enum DISP_CHANGE : int { Successful = 0, Restart = 1, Failed = -1, BadMode = -2, NotUpdated = -3, BadFlags = -4, BadParam = -5, BadDualView = -6 } [Flags()] internal enum DisplayDeviceStateFlags : int { AttachedToDesktop = 0x1, MultiDriver = 0x2, PrimaryDevice = 0x4, MirroringDriver = 0x8, VGACompatible = 0x10, Removable = 0x20, ModesPruned = 0x8000000, Remote = 0x4000000, Disconnect = 0x2000000 } [Flags()] internal enum DisplaySettingsFlags : int { 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 } [Flags()] internal enum DM : int { Orientation = 0x00000001, PaperSize = 0x00000002, PaperLength = 0x00000004, PaperWidth = 0x00000008, Scale = 0x00000010, Position = 0x00000020, NUP = 0x00000040, DisplayOrientation = 0x00000080, Copies = 0x00000100, DefaultSource = 0x00000200, PrintQuality = 0x00000400, Color = 0x00000800, Duplex = 0x00001000, YResolution = 0x00002000, TTOption = 0x00004000, Collate = 0x00008000, FormName = 0x00010000, LogPixels = 0x00020000, BitsPerPixel = 0x00040000, PelsWidth = 0x00080000, PelsHeight = 0x00100000, DisplayFlags = 0x00200000, DisplayFrequency = 0x00400000, ICMMethod = 0x00800000, ICMIntent = 0x01000000, MediaType = 0x02000000, DitherType = 0x04000000, PanningWidth = 0x08000000, PanningHeight = 0x10000000, DisplayFixedOutput = 0x20000000 }
VB.NET
Friend Enum DISP_CHANGE Successful = 0 Restart = 1 Failed = -1 BadMode = -2 NotUpdated = -3 BadFlags = -4 BadParam = -5 BadDualView = -6 End Enum <Flags()> Friend Enum DisplayDeviceStateFlags AttachedToDesktop = &H1 MultiDriver = &H2 PrimaryDevice = &H4 MirroringDriver = &H8 VGACompatible = &H10 Removable = &H20 ModesPruned = &H8000000 Remote = &H4000000 Disconnect = &H2000000 End Enum <Flags()> Friend Enum DisplaySettingsFlags CDS_NONE = 0 CDS_UPDATEREGISTRY = &H1 CDS_TEST = &H2 CDS_FULLSCREEN = &H4 CDS_GLOBAL = &H8 CDS_SET_PRIMARY = &H10 CDS_VIDEOPARAMETERS = &H20 CDS_ENABLE_UNSAFE_MODES = &H100 CDS_DISABLE_UNSAFE_MODES = &H200 CDS_RESET = &H40000000 CDS_RESET_EX = &H20000000 CDS_NORESET = &H10000000 End Enum <Flags()> Friend Enum DM Orientation = &H1 PaperSize = &H2 PaperLength = &H4 PaperWidth = &H8 Scale = &H10 Position = &H20 NUP = &H40 DisplayOrientation = &H80 Copies = &H100 DefaultSource = &H200 PrintQuality = &H400 Color = &H800 Duplex = &H1000 YResolution = &H2000 TTOption = &H4000 Collate = &H8000 FormName = &H10000 LogPixels = &H20000 BitsPerPixel = &H40000 PelsWidth = &H80000 PelsHeight = &H100000 DisplayFlags = &H200000 DisplayFrequency = &H400000 ICMMethod = &H800000 ICMIntent = &H1000000 MediaType = &H2000000 DitherType = &H4000000 PanningWidth = &H8000000 PanningHeight = &H10000000 DisplayFixedOutput = &H20000000 End Enum
DISP_CHANGE supplies the methods with results after the Display has been changed. These include Successful or Failed. DisplayDeviceStateFlags indicates how the device is attached to the computer. For example: Am I connected to this device through a remote connection, or is the screen connected to the current PC requesting a change of screen settings? DisplaySettingsFlags enables you to specify how the computer must store the change made to the display device. For example: If you were to supply the UPDATE_REGISTRY value, the PC will note this change in the computer’s Registry. The next time you start your PC, the changes will still be the same as you set them. Or temporary. DM specifies which screen setting you are changing. For example: Orientation.
Add a class to your project and name it clsDisplaySettings. This class will be responsible for all the Rotating and Resetting methods. Add the following Enumeration.
C#
public enum Orientation { DEGREES_CW_270 = 1, DEGREES_CW_180 = 2, DEGREES_CW_90 = 3, DEGREES_CW_0 = 0 }
VB.NET
Public Class clsDisplaySettings Public Enum Orientation DEGREES_CW_270 = 1 DEGREES_CW_180 = 2 DEGREES_CW_90 = 3 DEGREES_CW_0 = 0 End Enum
This enumeration simply indicates how many degrees the screen most rotate. Add the Rotate method.
C#
public static bool Rotate(uint uDisplay, Orientation oOrientation) { bool bResult = false; DISPLAY_DEVICE dDevice = new DISPLAY_DEVICE(); DEVMODE dmMode = new DEVMODE(); dDevice.cb = Marshal.SizeOf(dDevice); if (!APIStuff.EnumDisplayDevices(null, uDisplay - 1, ref dDevice, 0)) return false; if (0 != APIStuff.EnumDisplaySettings( dDevice.DeviceName, APIStuff.ENUM_CURRENT_SETTINGS, ref dmMode)) { if ((dmMode.dmDisplayOrientation + (int)oOrientation) % 2 == 1) { int tmp = dmMode.dmPelsHeight; dmMode.dmPelsHeight = dmMode.dmPelsWidth; dmMode.dmPelsWidth = tmp; } switch (oOrientation) { case Orientation.DEGREES_CW_90: dmMode.dmDisplayOrientation = APIStuff.DMDO_270; break; case Orientation.DEGREES_CW_180: dmMode.dmDisplayOrientation = APIStuff.DMDO_180; break; case Orientation.DEGREES_CW_270: dmMode.dmDisplayOrientation = APIStuff.DMDO_90; break; case Orientation.DEGREES_CW_0: dmMode.dmDisplayOrientation = APIStuff.DMDO_DEFAULT; break; default: break; } DISP_CHANGE ret = APIStuff.ChangeDisplaySettingsEx (dDevice.DeviceName, ref dmMode, IntPtr.Zero, DisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero); bResult = ret == 0; } return bResult; }
VB.NET
Public Shared Function Rotate(ByVal uDisplay As UInteger, _ ByVal oOrientation As Orientation) As Boolean Dim bResult As Boolean = False Dim dDevice As DISPLAY_DEVICE = New DISPLAY_DEVICE() Dim dmMode As DEVMODE = New DEVMODE() dDevice.cb = Marshal.SizeOf(dDevice) If Not APIStuff.EnumDisplayDevices(Nothing, uDisplay - 1, _ dDevice, 0) Then Return False If 0 <> APIStuff.EnumDisplaySettings _ (dDevice.DeviceName, APIStuff.ENUM_CURRENT_SETTINGS, _ dmMode) Then If (dmMode.dmDisplayOrientation + CInt(oOrientation)) _ Mod 2 = 1 Then Dim tmp As Integer = dmMode.dmPelsHeight dmMode.dmPelsHeight = dmMode.dmPelsWidth dmMode.dmPelsWidth = tmp End If Select Case oOrientation Case Orientation.DEGREES_CW_90 dmMode.dmDisplayOrientation = APIStuff.DMDO_270 Case Orientation.DEGREES_CW_180 dmMode.dmDisplayOrientation = APIStuff.DMDO_180 Case Orientation.DEGREES_CW_270 dmMode.dmDisplayOrientation = APIStuff.DMDO_90 Case Orientation.DEGREES_CW_0 dmMode.dmDisplayOrientation = APIStuff.DMDO_DEFAULT Case Else End Select Dim ret As DISP_CHANGE = APIStuff.ChangeDisplaySettingsEx _ (dDevice.DeviceName, dmMode, IntPtr.Zero, _ DisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero) bResult = ret = 0 End If Return bResult End Function
The preceding code rotates your specified screen. Add the Reset method, which resets all screens back to their default values.
C#
public static void Reset() { try { uint i = 0; while (++i <= 64) { Rotate(i, Orientation.DEGREES_CW_0); } } catch (ArgumentOutOfRangeException ex) { } }
VB.NET
Public Shared Sub Reset() Try Dim i As Integer = 0 While System.Threading.Interlocked.Increment(i) <= 64 Rotate(i, Orientation.DEGREES_CW_0) End While Catch ex As ArgumentOutOfRangeException End Try End Sub
On your form, add the following code for your buttons.
C#
private void button1_Click(object sender, EventArgs e) { clsDisplaySettings.Rotate(1, clsDisplaySettings.Orientation.DEGREES_CW_0); } private void button2_Click(object sender, EventArgs e) { clsDisplaySettings.Rotate(2, clsDisplaySettings.Orientation.DEGREES_CW_180); } private void button3_Click(object sender, EventArgs e) { clsDisplaySettings.Rotate(3, clsDisplaySettings.Orientation.DEGREES_CW_270); } private void button4_Click(object sender, EventArgs e) { clsDisplaySettings.Reset(); }
VB.NET
Private Sub button1_Click(ByVal sender As Object, ByVal e _ As EventArgs) Handles button1.Click clsDisplaySettings.Rotate(1, clsDisplaySettings.Orientation _ .DEGREES_CW_0) End Sub Private Sub button2_Click(ByVal sender As Object, ByVal e _ As EventArgs) Handles button2.Click clsDisplaySettings.Rotate(2, clsDisplaySettings _ .Orientation.DEGREES_CW_180) End Sub Private Sub button3_Click(ByVal sender As Object, ByVal e _ As EventArgs) Handles button3.Click clsDisplaySettings.Rotate(3, clsDisplaySettings.Orientation _ .DEGREES_CW_270) End Sub Private Sub button4_Click(ByVal sender As Object, ByVal e _ As EventArgs) Handles button4.Click clsDisplaySettings.Reset() End Sub
Conclusion
It is quite easy to “play” with your desktop resolution, as you saw. I use it to prank my co-workers; I hope you put this knowledge to better use than I.