Setting Dual Monitor Resolution with VB.NET 2012

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!

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read