18

How do I adjust the screen brightness in C#?

Adam Michalik
  • 9,678
  • 13
  • 71
  • 102
Steven
  • 2,148
  • 8
  • 33
  • 50

5 Answers5

9

Look at the SetDeviceGammaRamp API function. There's a CodeProject article that describes using it from C# here: Setting Screen Brightness in C#

Be aware that your graphics card has to support this though, I'd assume that most modern ones do, but I don't know.

Edit: Since the CodeProject article seems to be down, another place to find out how to call it from C# is on the pInvoke site.

Hans Olsson
  • 54,199
  • 15
  • 94
  • 116
8

Here is code that changes brightness in Windows's settings (suitable for laptops):

using System;
using System.Management;

public static class WindowsSettingsBrightnessController
{
    public static int Get()
    {
        using var mclass = new ManagementClass("WmiMonitorBrightness")
        {
            Scope = new ManagementScope(@"\\.\root\wmi")
        };
        using var instances = mclass.GetInstances();
        foreach (ManagementObject instance in instances)
        {
            return (byte)instance.GetPropertyValue("CurrentBrightness");
        }
        return 0;
    }

    public static void Set(int brightness)
    {
        using var mclass = new ManagementClass("WmiMonitorBrightnessMethods")
        {
            Scope = new ManagementScope(@"\\.\root\wmi")
        };
        using var instances = mclass.GetInstances();
        var args = new object[] { 1, brightness };
        foreach (ManagementObject instance in instances)
        {
            instance.InvokeMethod("WmiSetBrightness", args);
        }
    }
}

And here is code to change brightness and an external monitor(s) (but won't work for built-in ones like on laptops).

This code is modified version of @help's code that uses EnumDisplayMonitors instead of MonitorFromWindow, so it doesn't need window to run and searches for all monitors and not only for one window is on right now.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

public class PhysicalMonitorBrightnessController : IDisposable
{
    #region DllImport
    [DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);

    [DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray);

    [DllImport("dxva2.dll", EntryPoint = "GetMonitorBrightness")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetMonitorBrightness(IntPtr handle, ref uint minimumBrightness, ref uint currentBrightness, ref uint maxBrightness);

    [DllImport("dxva2.dll", EntryPoint = "SetMonitorBrightness")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetMonitorBrightness(IntPtr handle, uint newBrightness);

    [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitor")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool DestroyPhysicalMonitor(IntPtr hMonitor);
        
    [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DestroyPhysicalMonitors(uint dwPhysicalMonitorArraySize, [In] PHYSICAL_MONITOR[] pPhysicalMonitorArray);

    [DllImport("user32.dll")]
    static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, EnumMonitorsDelegate lpfnEnum, IntPtr dwData);
    delegate bool EnumMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData);
    #endregion

    private IReadOnlyCollection<MonitorInfo> Monitors { get; set; }

    public PhysicalMonitorBrightnessController()
    {
        UpdateMonitors();
    }

    #region Get & Set
    public void Set(uint brightness)
    {
        Set(brightness, true);
    }

    private void Set(uint brightness, bool refreshMonitorsIfNeeded)
    {
        bool isSomeFail = false;
        foreach (var monitor in Monitors)
        {
            uint realNewValue = (monitor.MaxValue - monitor.MinValue) * brightness / 100 + monitor.MinValue;
            if (SetMonitorBrightness(monitor.Handle, realNewValue))
            {
                monitor.CurrentValue = realNewValue;
            }
            else if (refreshMonitorsIfNeeded)
            {
                isSomeFail = true;
                break;
            }
        }

        if (refreshMonitorsIfNeeded && (isSomeFail || !Monitors.Any()))
        {
            UpdateMonitors();
            Set(brightness, false);
            return;
        }
    }

    public int Get()
    {
        if (!Monitors.Any())
        {
            return -1;
        }
        return (int)Monitors.Average(d => d.CurrentValue);
    }
    #endregion

    private void UpdateMonitors()
    {
        DisposeMonitors(this.Monitors);

        var monitors = new List<MonitorInfo>();
        EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) =>
        {
            uint physicalMonitorsCount = 0;
            if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, ref physicalMonitorsCount))
            {
                // Cannot get monitor count
                return true;
            }

            var physicalMonitors = new PHYSICAL_MONITOR[physicalMonitorsCount];
            if (!GetPhysicalMonitorsFromHMONITOR(hMonitor, physicalMonitorsCount, physicalMonitors))
            {
                // Cannot get physical monitor handle
                return true;
            }

            foreach (PHYSICAL_MONITOR physicalMonitor in physicalMonitors)
            {
                uint minValue = 0, currentValue = 0, maxValue = 0;
                if (!GetMonitorBrightness(physicalMonitor.hPhysicalMonitor, ref minValue, ref currentValue, ref maxValue))
                {
                    DestroyPhysicalMonitor(physicalMonitor.hPhysicalMonitor);
                    continue;
                }

                var info = new MonitorInfo
                {
                    Handle = physicalMonitor.hPhysicalMonitor,
                    MinValue = minValue,
                    CurrentValue = currentValue,
                    MaxValue = maxValue,
                };
                monitors.Add(info);
            }

            return true;
        }, IntPtr.Zero);

        this.Monitors = monitors;
    }

    public void Dispose()
    {
        DisposeMonitors(Monitors);
        GC.SuppressFinalize(this);
    }

    private static void DisposeMonitors(IEnumerable<MonitorInfo> monitors)
    {
        if (monitors?.Any() == true)
        {
            PHYSICAL_MONITOR[] monitorArray = monitors.Select(m => new PHYSICAL_MONITOR { hPhysicalMonitor = m.Handle }).ToArray();
            DestroyPhysicalMonitors((uint)monitorArray.Length, monitorArray);
        }
    }

    #region Classes
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct PHYSICAL_MONITOR
    {
        public IntPtr hPhysicalMonitor;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string szPhysicalMonitorDescription;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct Rect
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

    public class MonitorInfo
    {
        public uint MinValue { get; set; }
        public uint MaxValue { get; set; }
        public IntPtr Handle { get; set; }
        public uint CurrentValue { get; set; }
    }
    #endregion
}
NetMage
  • 26,163
  • 3
  • 34
  • 55
maxc137
  • 2,291
  • 3
  • 20
  • 32
  • This changes the brightness from the windows settings, which works for the internal screen of the laptop. That doesn't work for external screens over HDMI but for this case the answer from @help worked for me. – Coden Aug 04 '20 at 07:32
  • 1
    @Apfelkuacha You are right! I didn't think changing brightness on external monitors was even possible. Added modified version of help's code that uses `EnumDisplayMonitors` instead of `MonitorFromWindow` to this answer. – maxc137 Aug 09 '20 at 21:39
  • This should be marked as the answer. Thank you maxc137. – T3chDad Nov 11 '21 at 17:32
5
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PHYSICAL_MONITOR
{
    public IntPtr hPhysicalMonitor;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string szPhysicalMonitorDescription;
}

public class BrightnessController : IDisposable
{
    [DllImport("user32.dll", EntryPoint = "MonitorFromWindow")]
    public static extern IntPtr MonitorFromWindow([In] IntPtr hwnd, uint dwFlags);

    [DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DestroyPhysicalMonitors(uint dwPhysicalMonitorArraySize, ref PHYSICAL_MONITOR[] pPhysicalMonitorArray);

    [DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);

    [DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray);

    [DllImport("dxva2.dll", EntryPoint = "GetMonitorBrightness")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetMonitorBrightness(IntPtr handle, ref uint minimumBrightness, ref uint currentBrightness, ref uint maxBrightness);

    [DllImport("dxva2.dll", EntryPoint = "SetMonitorBrightness")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetMonitorBrightness(IntPtr handle, uint newBrightness);

    private uint _physicalMonitorsCount = 0;
    private PHYSICAL_MONITOR[] _physicalMonitorArray;

    private IntPtr _firstMonitorHandle;

    private uint _minValue = 0;
    private uint _maxValue = 0;
    private uint _currentValue = 0;

    public BrightnessController(IntPtr windowHandle)
    {
        uint dwFlags = 0u;
        IntPtr ptr = MonitorFromWindow(windowHandle, dwFlags);
        if (!GetNumberOfPhysicalMonitorsFromHMONITOR(ptr, ref _physicalMonitorsCount))
        {
            throw new Exception("Cannot get monitor count!");
        }
        _physicalMonitorArray = new PHYSICAL_MONITOR[_physicalMonitorsCount];

        if (!GetPhysicalMonitorsFromHMONITOR(ptr, _physicalMonitorsCount, _physicalMonitorArray))
        {
            throw new Exception("Cannot get physical monitor handle!");
        }
        _firstMonitorHandle = _physicalMonitorArray[0].hPhysicalMonitor;

        if (!GetMonitorBrightness(_firstMonitorHandle, ref _minValue, ref _currentValue, ref _maxValue))
        {
            throw new Exception("Cannot get monitor brightness!");
        }
    }

    public void SetBrightness(int newValue) // 0 ~ 100
    {
        newValue = Math.Min(newValue, Math.Max(0, newValue));
        _currentValue = (_maxValue - _minValue) * (uint)newValue / 100u + _minValue;
        SetMonitorBrightness(_firstMonitorHandle, _currentValue);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_physicalMonitorsCount > 0)
            {
                DestroyPhysicalMonitors(_physicalMonitorsCount, ref _physicalMonitorArray);
            }
        }
    }
}
NetMage
  • 26,163
  • 3
  • 34
  • 55
help
  • 87
  • 1
  • 6
  • That Answer without any text next to the code works. Yeah! It simply works and sets the brightness of my monitor. – Coden Jul 30 '20 at 15:22
  • Here is a tip to get the window handle to pass to the constructor from WPF: IntPtr windowHandle = new System.Windows.Interop.WindowInteropHelper(theMainWindow).Handle; (Where x:Name="theMainWindow" in MainWindow.xaml) Then call the BrightnessController constructor in window Loaded event – sergeantKK Jan 13 '21 at 14:22
  • Isn't there an error in `SetBrightness` where `newvalue = Math.Min(newValue, Math.Max(0, newValue));` which I assume was meant to constrain `newvalue` to `0` - `100` so should have `100` as the first parameter to `Math.Min`? – NetMage Sep 24 '21 at 21:48
  • I highly advise against using this code: "DestroyPhysicalMonitors(_phys". Or can you buy a new monitor each time? – tmighty Jan 03 '22 at 20:22
3

Just found the SetMonitorBrightness function on MSDN.

uTILLIty
  • 473
  • 4
  • 9
  • 1
    Have you managed to implement this function? Other methods mentioned here do not work under all circumstances, especially when two video cards are connected (using PCI-E and legacy PCI slots) under Windows 10. – W.M. Dec 24 '16 at 09:20
  • The answer from @help is using that function and it works on an external monitor over HDMI – Coden Aug 04 '20 at 07:11
0

I tested the below code on my tablet and laptops work. You need to add a reference System.Management, find in the NuGet. This changes the actual brightness of the monitor.

//get the actual percentage of brightness
static int GetCurrentBrightness()
{
    //define scope (namespace)
    System.Management.ManagementScope s = new System.Management.ManagementScope("root\\WMI");
    //define query
    System.Management.SelectQuery q = new System.Management.SelectQuery("WmiMonitorBrightness");
    //output current brightness
    System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(s, q);
    System.Management.ManagementObjectCollection moc = mos.Get();
    //store result
    byte curBrightness = 0;
    foreach (System.Management.ManagementObject o in moc)
    {
        curBrightness = (byte)o.GetPropertyValue("CurrentBrightness");
        break; //only work on the first object
    }
    moc.Dispose();
    mos.Dispose();
    return (int)curBrightness;
}

//array of valid brightness values in percent
static byte[] GetBrightnessLevels()
{
    //define scope (namespace)
    System.Management.ManagementScope s = new System.Management.ManagementScope("root\\WMI");
    //define query
    System.Management.SelectQuery q = new System.Management.SelectQuery("WmiMonitorBrightness");
    //output current brightness
    System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(s, q);
    byte[] BrightnessLevels = new byte[0];
    try
    {
        System.Management.ManagementObjectCollection moc = mos.Get();
        //store result
        foreach (System.Management.ManagementObject o in moc)
        {
            BrightnessLevels = (byte[])o.GetPropertyValue("Level");
            break; //only work on the first object
        }
        moc.Dispose();
        mos.Dispose();

    }
    catch (Exception)
    {
        MessageBox.Show("Sorry, Your System does not support this brightness control...");
    }
    return BrightnessLevels;
}

static void SetBrightness(byte targetBrightness)
{
    //define scope (namespace)
    System.Management.ManagementScope s = new System.Management.ManagementScope("root\\WMI");
    //define query
    System.Management.SelectQuery q = new System.Management.SelectQuery("WmiMonitorBrightnessMethods");
    //output current brightness
    System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(s, q);
    System.Management.ManagementObjectCollection moc = mos.Get();
    foreach (System.Management.ManagementObject o in moc)
    {
        o.InvokeMethod("WmiSetBrightness", new Object[] { UInt32.MaxValue, targetBrightness });
        //note the reversed order - won't work otherwise!
        break; //only work on the first object
    }

    moc.Dispose();
    mos.Dispose();
}

Above Got from: https://www.codeproject.com/Articles/236898/Screen-Brightness-Control-for-Laptops-and-Tablets

Haryono
  • 2,184
  • 1
  • 21
  • 14