One monitor has never been enough. As a programmer / trainer / web designer I always need more space. Whether it is on my table ( mostly ) or on my screen. Not too long ago I had the unfortunate pleasure of having my computer’s hard disk crash. Luckily I had enough backups (3 in total), but I still lost some things.
To make a long story short, I got a new computer and took the opportunity to buy an additional screen. I now know what Heaven feels like – if only I could get a much bigger table, because I have now much less space…
Because I have two monitors now, it can be quite cumbersome to change the display settings depending on my needs, I decided to make this little program that can change both monitors’ resolution for me.
Erm, there is only one button on my VB.NET 2012 form, so I won’t explain how to add a single button on a single form.
First piece of business (as usual) is to add the namespaces needed in our project:
Imports System.Runtime.InteropServices 'APIs
Let us now add the APIs in order to get and set screen resolutions for both our monitors:
'This function obtains information about the display devices in a system <DllImport("user32.dll")> _ Private Shared Function EnumDisplayDevices(ByVal Unused As Integer, _ ByVal iDevNum As Short, ByRef lpDisplayDevice As DISPLAY_DEVICE, ByVal dwFlags As Integer) As Integer End Function 'This function retrieves information about one of the graphics modes for a display device <DllImport("user32.dll")> _ Private Shared Function EnumDisplaySettings(ByVal lpszDeviceName As String, _ ByVal iModeNum As Integer, ByRef lpDevMode As DEVMODE) As Integer End Function 'The ChangeDisplaySettingsEx function changes the settings of the specified display device to the specified graphics mode <DllImport("user32.dll")> _ Private Shared Function ChangeDisplaySettingsEx(ByVal lpszDeviceName As String, _ ByRef lpDevMode As DEVMODE, ByVal hWnd As Integer, ByVal dwFlags As Integer, _ ByVal lParam As Integer) As Integer End Function
First, we will use the EnumDisplayDevices to determine how many display devices are connected to the PC, then we obtain the current monitor settings with the use of the EnumDisplaySettings API. Lastly, we will make use of the ChangeDisplaySettingsEx API to change the settings for both monitors to our desired resolution.
Obviously, our APIs still need their constants and structures that make them work. Let us add them now:
'Constants Part of DEVMODE Structure that is used for specifying characteristics of display and print devices Private Const CCDEVICENAME As Short = 32 Private Const CCFORMNAME As Short = 32 Private Const DM_BITSPERPEL = &H40000 Private Const DM_PELSWIDTH = &H80000 Private Const DM_PELSHEIGHT = &H100000 Private Const CDS_UPDATEREGISTRY = &H1 Private Const DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = &H1 'Display Device Attached To Desktop Device Private Const DISPLAY_PRIMARY_DEVICE = &H4 'Primary Display Device 'This structure defines various properties about a display device Private Structure DISPLAY_DEVICE Public cb As Integer <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCDEVICENAME)> _ Public DeviceName As String <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> _ Public DeviceString As String Public StateFlags As Short <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> _ Public DeviceID As String <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> _ Public DeviceKey As String End Structure 'Specify characteristics of display and print devices Private Structure DEVMODE <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCDEVICENAME)> _ Public dmDeviceName As String Public dmSpecVersion As Short Public dmDriverVersion As Short Public dmSize As Short Public dmDriverExtra As Short Public dmFields As Integer Public dmOrientation As Short Public dmPaperSize As Short Public dmPaperLength As Short Public dmPaperWidth As Short Public dmScale As Short Public dmCopies As Short Public dmDefaultSource As Short Public dmPrintQuality As Short Public dmColor As Short Public dmDuplex As Short Public dmYResolution As Short Public dmTTOption As Short Public dmCollate As Short <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCFORMNAME)> _ Public dmFormName As String Public dmLogPixels As Short Public dmBitsPerPel As Short Public dmPelsWidth As Integer Public dmPelsHeight As Integer Public dmDisplayFlags As Integer Public dmDisplayFrequency As Integer Public dmICMMethod As Integer Public dmICMIntent As Integer Public dmMediaType As Integer Public dmDitherType As Integer Public dmReserved1 As Integer Public dmReserved2 As Integer Public dmPanningWidth As Integer Public dmPanningHeight As Integer End Structure
We declared the DISPLAY_DEVICE and DEVMODE Structures, for more information on them have a look here and here. All that is left now, is to connect the dots, let’s add the following code behind our button:
Private Sub btnSet_Click(sender As Object, e As EventArgs) Handles btnSet.Click Dim dmCurrResolution As DEVMODE 'Create Resolution Object Dim dmResolutions() As DEVMODE 'Create Resolution Array Because There Will Be More Than One Screen Dim ddCurrDisplay As DISPLAY_DEVICE 'Create DisplayDevice Object Dim ddDevices() As DISPLAY_DEVICE 'Create Display Device Array Because There Will Be More Than One Screen Dim intResult As Integer = 1 'Result Of EnumDisplayDevices API Call Dim sMonitors As Short 'How Many Monitors? 'Loop Through All Available Monitors And get Their Current Settings Do While intResult <> 0 'Do While There Are Monitors ddCurrDisplay.cb = Marshal.SizeOf(ddCurrDisplay) 'Initialize Current Display Object dmCurrResolution.dmSize = Marshal.SizeOf(dmCurrResolution) 'get Size intResult = EnumDisplayDevices(0, sMonitors, ddCurrDisplay, 0) 'Determine Number Of Monitors 'Determine How Monitors Are Connected To System If ddCurrDisplay.StateFlags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP Or _ ddCurrDisplay.StateFlags = DISPLAY_PRIMARY_DEVICE Or _ ddCurrDisplay.StateFlags = (DISPLAY_DEVICE_ATTACHED_TO_DESKTOP Or DISPLAY_PRIMARY_DEVICE) Then ReDim Preserve ddDevices(sMonitors) 'Allocate Space For Each Monitor In Array ddDevices(sMonitors) = ddCurrDisplay 'Store Their Settings End If sMonitors += 1 'Increment Loop 'Loop Through All Monitors And Set Resolution For sMonitors = 0 To UBound(ddDevices) ReDim Preserve dmResolutions(sMonitors) dmResolutions(sMonitors).dmSize = Marshal.SizeOf(dmResolutions(sMonitors)) 'Determine Size dmResolutions(sMonitors).dmFields = DM_PELSWIDTH Or DM_PELSHEIGHT Or DM_BITSPERPEL 'Get Settings dmResolutions(sMonitors).dmPelsWidth = 1024 'Change X dmResolutions(sMonitors).dmPelsHeight = 768 'Change Y dmResolutions(sMonitors).dmBitsPerPel = 32 ' Use Correct BPP Setting, Could Be 8, 16, 32 Or 4 'Change intResult = ChangeDisplaySettingsEx(ddDevices(sMonitors).DeviceName, dmResolutions(sMonitors), 0, CDS_UPDATEREGISTRY, 0) If intResult = -1 Then 'Error Thrown MessageBox.Show("Invalid Setting") End If Next End Sub
We determine how many monitors are connected to the PC as well as how they are connected. Based on that, we retrieve their current resolution settings. After this, we loop through each monitor object and change each monitor’s resolution to 1024 x 768 and update the registry.
If an invalid setting is supplied a message box will inform us.
I hope you have enjoyed this article and that you have learned a thing or two from it. Until next time!