使用C#调整屏幕亮度

18

我如何在C#中调整屏幕亮度?

5个回答

9
看看 SetDeviceGammaRamp API 函数。这里有一篇 CodeProject 文章描述了如何在 C# 中使用它:设置屏幕亮度在 C# 中
请注意,您的显卡必须支持此功能,我认为大多数现代显卡都支持,但我不确定。
编辑:由于 CodeProject 文章似乎已经关闭,另一个学习如何从 C# 调用它的好地方是在 pInvoke 网站 上。

9
这不是真正的亮度,而是伽马值。这只是亮度的一种错觉。 - cricardol
1
嗯,而且CodeProject的链接已经失效了。考虑到CodeProject是什么样的网站,这也许并不是什么坏事。 - IInspectable
@IInspectable 谢谢,已经用另一个链接更新了答案。 - Hans Olsson

8

这里是更改Windows设置中亮度的代码(适用于笔记本电脑):

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);
        }
    }
}

这里是改变亮度和连接外部显示器的代码(但对于像笔记本电脑上内置的显示器不起作用)。

这段代码是@help的代码的修改版本,它使用EnumDisplayMonitors而不是MonitorFromWindow,因此不需要窗口运行并搜索所有监视器,而不仅仅是当前窗口所在的一个。

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
}

这会改变从Windows设置中的亮度,适用于笔记本电脑的内部屏幕。但对于通过HDMI连接的外部屏幕则不起作用,但在这种情况下,@help的答案对我有用。 - Coden
1
@Apfelkuacha 你说得对!我甚至没有想到在外部显示器上改变亮度是可能的。我在这个答案中添加了一个修改过的帮助代码版本,它使用 EnumDisplayMonitors 而不是 MonitorFromWindow - maxc137
这应该被标记为答案。谢谢maxc137。 - T3chDad

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);
            }
        }
    }
}

那个没有代码旁边的答案是有效的。 耶!它简单地工作并设置了我的显示器的亮度。 - Coden
这里有一个提示,可以获取WPF窗口句柄并传递给构造函数: IntPtr windowHandle = new System.Windows.Interop.WindowInteropHelper(theMainWindow).Handle; (其中MainWindow.xaml中x:Name="theMainWindow") 然后在窗口Loaded事件中调用BrightnessController构造函数。 - sergeantKK
SetBrightness 函数中有一个错误吧:newvalue = Math.Min(newValue, Math.Max(0, newValue)); 我想应该是将 newvalue 限制在 0-100 的范围内,所以第一个参数应该是 100 才对吧? - NetMage
我强烈建议不要使用这段代码:“DestroyPhysicalMonitors(_phys”。或者你每次都可以买一台新的显示器吗? - tmighty

3

我在MSDN上找到了SetMonitorBrightness函数。


1
你已成功实现了这个函数吗?其他在这里提到的方法并不能在所有情况下都奏效,尤其是在使用 Windows 10 的 PCI-E 和传统 PCI 插槽连接两张显卡时。 - W.M.
@help 的答案是使用那个函数,并且它在通过 HDMI 连接的外部显示器上运行。 - Coden

0
我在我的平板电脑和笔记本电脑上测试了下面的代码。 您需要添加一个 System.Management 引用,在 NuGet 中找到它。 这会更改监视器的实际亮度。
//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();
}

从上面获取: https://www.codeproject.com/Articles/236898/Screen-Brightness-Control-for-Laptops-and-Tablets

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接