Manipulating Monitor Brightness in Visual Basic

Introduction

Curiosity killed the cat; well, perhaps one day. Today’s article will focus on how to adjust your monitor’s brightness with your Visual basic program. Sounds like fun? Good; let’s get started.

But first, the boring stuff…

The Windows API

I have explained the Windows API on numerous occasions in the past, so please have a read through these articles about the Windows API before continuing this article.

Why am I talking about the API? Well, it’s not possible to set the monitor’s brightness through the .NET Framework alone, because it is a built-in Windows feature that uses built-in Windows code.

Our Project

Today, you will create a project that will change the monitor’s brightness. It is a lot of work, and a tad complicated, so let’s get started.

Create a new Visual Basic Windows Forms project. You may name it anything you like. It isn’t much of a design. If you want, you can add a Trackbar component to the Form, but we will add one during run time in any case.

Code

To start, add the necessary Imports Statement on top of your code, for the API declarations to work. If you have gone through the previous links detailing the ins and outs of APIs, you should know the purpose of this namespace. If you haven’t, I suggest you do so before continuing.

Imports System.Runtime.InteropServices

Add the Colour_Ramp structure:

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
   Private Structure COLOUR_RAMP

   <MarshalAs(UnmanagedType.ByValArray, SizeConst:=256)> _
      Public uiRed As UInt16()
   <MarshalAs(UnmanagedType.ByValArray, SizeConst:=256)> _
      Public uiGreen As UInt16()
   <MarshalAs(UnmanagedType.ByValArray, SizeConst:=256)> _
      Public uiBlue As UInt16()

End Structure

It looks scarier than what it actually is. If this is your first time encountering the term “Structure“, I suggest you have a decent read-through here.

If you do not know the difference between Managed and Unmanaged Types, have a read through here.

Anything coming from an API is always unmanaged. This may cause some problems in how the .NET Framework might interpret the type of data that it has received. In the preceding code segment, I made sure that our program will be able to understand the type of data that the Red, Green, and Blue items will send.

You will also notice that I have included a SizeConst. This sets the items’ size to 256. Why 256? The computer’s screen can show over 16 million colors, nowadays perhaps even more. Each color that you see on your monitor is a combination of Red, Green, and Blue. Each one of these has 256 different shades. If you do the math, you’ll get a figure slightly higher than 16 million.

Another interesting thing that you may have noticed is the fact that all of the datatypes are UInt16. This is an Unsigned Integer. If you do not know the difference between Signed and Unsigned datatypes, have a look here.

How Does RGB Work?

RGB is a color model used in computer screens. As I said, each element contains 256 different shades, and all colors are ultimately made up of the numeric combination. Here are a few examples:

The RGB value 0,0,0 will give black. Here are some others:

  • 255, 255, 255 will give you white.
  • 128, 128, 128 will give you gray.
  • 255, 0, 0 will give you red.
  • 0, 255, 0, will give you green
  • 0, 0, 255 will give you blue.
  • 255, 0, 255 will give you magenta.

Here is a list of possible RGB combinations

Add the following APIs:

<DllImport("gdi32.dll")> _
   Private Shared Function SetDeviceGammaRamp(ByVal hDC As IntPtr, _
      ByRef lpRamp As COLOUR_RAMP) As Boolean
End Function

<DllImport("user32.dll")> _
   Private Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
End Function

<DllImport("gdi32.dll")> _
   Private Shared Function GetDeviceGammaRamp(ByVal hdc As Int32, _
      ByRef lpv As COLOUR_RAMP) As Boolean
End Function

For a decent explanation on these three APIs, have a look at the following:

Declare the following variables:

Private Shared crRamp As New COLOUR_RAMP()
Private Shared crTempRamp As New COLOUR_RAMP()

crRamp will hold the brightness values as they are being changed. crTempRamp will hold the value of the brightness before any changes so that we can reset the brightness when the form closes.

Add the Form_Load event:

Private Sub Form1_Load(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles Me.Load

   GetDeviceGammaRamp(GetDC(IntPtr.Zero), crTempRamp)

   blnLoaded = True

End Sub

In the Form_Load event, I simply get the device context of the current displaying device, which is the monitor, and then store the brightness value inside the crTempRamp variable so that we can change the brightness levels back upon closing.

Remember that this is system wide, so be careful not too play around too much.

Add the Form_Closing event now:

Private Sub SetBrightness_FormClosing(ByVal sender As Object, _
   ByVal e As System.Windows.Forms.FormClosingEventArgs) _
   Handles Me.FormClosing

   RestoreGamma(crTempRamp)

End Sub

As said, this simply returns the brightness levels back to what it was before any changes. You will add the RestoreGamma Sub procedure a bit later.

If you haven’t added a Trackbar during design time, create it now:

Private WithEvents tbBrightness _
   As System.Windows.Forms.TrackBar

Add its Scroll event as well:

Private Sub tbBrightness_Scroll(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles tbBrightness.Scroll

   SetGamma(tbBrightness.Value)

End Sub

As the Trackbar’s value changes via the user, a Sub procedure called SetGamma is called. Add the SetGamma Sub now:

Private Shared Sub SetGamma(ByVal intGamma As Integer)

   crRamp.uiRed   = New UShort(255) {}
   crRamp.uiGreen = New UShort(255) {}
   crRamp.uiBlue  = New UShort(255) {}

   For i As Integer = 1 To 255

      crRamp.uiRed(i) = _
         ExchangeColourValues(crRamp.uiGreen(i), _
         ExchangeColourValues(crRamp.uiBlue(i), _
         CUShort((Math.Min(65535, Math.Max(0, _
         Math.Pow((i + 1) / 256.0R, intGamma * 0.1) * _
         65535 + 0.5))))))

   Next

   SetDeviceGammaRamp(GetDC(IntPtr.Zero), crRamp)

End Sub

The first three lines in this Sub are not too complicated. The Red, Green, and Blue values simply get initialized as new Unsigned Short arrays, each with 256 elements inside.

A For loop is started; it will loop 256 times. The colors get calculated with a complex mathematic algorithm inside a call to a new method named ExchangeColourValues. Add this Function now:

Private Shared Function ExchangeColourValues(Of T) _
   (ByRef Target As T, ByVal CurrentValue As T) As T

   Target = CurrentValue

   Return CurrentValue

End Function

This Function makes use of Generic lists and Lists of Generic Lists. It simply gets the current color value and returns it, and then goes on to the next correct value. For more information on Generic Lists, read here.

Add the last Sub Procedure:

Private Shared Sub RestoreGamma(ByVal crGamma As COLOUR_RAMP)

   SetDeviceGammaRamp(GetDC(IntPtr.Zero), crGamma)

End Sub

This Sub restores the monitor’s brightness back to what it was, before it was changed, when your form closes.

I have attached a working sample with this article.

Conclusion

As you can see, changing your monitor’s brightness is not too complicated. I hope you have enjoyed today’s article. Until next time, cheers!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read