Introduction
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.
Design
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.
Code
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.
Conclusion
I hope you have enjoyed this article and that you have learned a thing or two from it. Until next time!