You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中关闭显示器/背光?解决SC_MONITORPOWER无信号问题

解决批量控制显示器无“No Signal”提示的问题

我完全理解你的痛点:用SC_MONITORPOWER关闭显示器时总会弹出“No Signal”的OSD提示,Standby状态还没法正常工作,手动去每台显示器关闭OSD更是不现实——毕竟要部署到1000台设备上。下面给你详细讲讲怎么用IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS实现需求,以及相关的注意事项。

为什么SC_MONITORPOWER会弹出“No Signal”?

SC_MONITORPOWER本质是让显卡停止向显示器输出信号,显示器检测不到输入就会触发内置的OSD提示。而Standby状态失效通常是因为显卡或显示器硬件不支持这个低功耗模式,没法通过系统命令触发。

用IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS控制背光(无信号中断)

这个API是直接控制显示器的背光亮度,不会切断显卡的信号输出,所以显示器不会弹出“No Signal”提示。它通过Windows的设备控制接口和显卡/显示器驱动交互,下面是C#的实现代码:

using System;
using System.Runtime.InteropServices;

public class DisplayController
{
    // 常量定义
    private const uint GENERIC_READ = 0x80000000;
    private const uint GENERIC_WRITE = 0x40000000;
    private const int FILE_SHARE_READ = 0x00000001;
    private const int FILE_SHARE_WRITE = 0x00000002;
    private const int OPEN_EXISTING = 3;
    private const uint IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS = 0x002D0106;

    // 亮度控制结构体
    [StructLayout(LayoutKind.Sequential)]
    private struct BrightnessParams
    {
        public uint DisplayPolicy; // 2=手动设置亮度,忽略AC/DC状态
        public uint ACBrightness;   // AC电源下亮度(0-100)
        public uint DCBrightness;   // DC电源下亮度(0-100)
    }

    // P/Invoke 系统函数
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool DeviceIoControl(
        IntPtr hDevice,
        uint dwIoControlCode,
        ref BrightnessParams lpInBuffer,
        uint nInBufferSize,
        IntPtr lpOutBuffer,
        uint nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);

    /// <summary>
    /// 设置显示器亮度
    /// </summary>
    /// <param name="brightness">亮度值0-100,0=关闭背光</param>
    /// <returns>是否设置成功</returns>
    public static bool SetDisplayBrightness(uint brightness)
    {
        // 先尝试打开主显示器设备
        IntPtr deviceHandle = CreateFile(
            @"\\.\DISPLAY1",
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            IntPtr.Zero,
            OPEN_EXISTING,
            0,
            IntPtr.Zero);

        // 如果主显示器打开失败,尝试第二台(多显示器场景)
        if (deviceHandle == IntPtr.Zero || deviceHandle == (IntPtr)(-1))
        {
            deviceHandle = CreateFile(
                @"\\.\DISPLAY2",
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                IntPtr.Zero,
                OPEN_EXISTING,
                0,
                IntPtr.Zero);
        }

        if (deviceHandle == IntPtr.Zero || deviceHandle == (IntPtr)(-1))
        {
            return false;
        }

        try
        {
            var brightnessData = new BrightnessParams
            {
                DisplayPolicy = 2, // 强制手动设置亮度
                ACBrightness = brightness,
                DCBrightness = brightness
            };

            uint bytesReturned;
            bool success = DeviceIoControl(
                deviceHandle,
                IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS,
                ref brightnessData,
                (uint)Marshal.SizeOf(typeof(BrightnessParams)),
                IntPtr.Zero,
                0,
                out bytesReturned,
                IntPtr.Zero);

            return success;
        }
        finally
        {
            // 无论成功失败都要关闭设备句柄
            CloseHandle(deviceHandle);
        }
    }

    // 快速关闭背光
    public static bool TurnOffBacklight() => SetDisplayBrightness(0);

    // 快速恢复背光(默认亮度100)
    public static bool TurnOnBacklight(uint defaultBrightness = 100) => SetDisplayBrightness(defaultBrightness);
}

使用说明和注意事项

  • 权限问题:部分Windows系统要求程序以管理员身份运行才能调用DeviceIoControl,部署时要确保程序有足够权限(可以在项目属性里设置“要求管理员权限”)。
  • 多显示器兼容:代码里只处理了DISPLAY1和DISPLAY2,如果是更多显示器的场景,你可以用EnumDisplayDevicesAPI枚举所有显示器设备,逐个打开并设置亮度。
  • 硬件兼容性:这个API依赖显卡和显示器驱动的支持,少数老设备可能不兼容。如果遇到这种情况,可以尝试另一种方案——DDC/CI协议控制,直接向显示器发送硬件级命令,但代码会更复杂,需要处理I2C通信。

替代方案:DDC/CI协议(如果IOCTL不兼容)

如果IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS在部分设备上失效,可以用DDC/CI协议直接控制显示器。这个协议是显示器行业标准,大部分现代显示器都支持,它通过显卡的I2C通道向显示器发送命令,比如关闭背光、切换输入源等。不过实现起来需要更多的P/Invoke代码,你可以基于Windows的硬件控制接口自行开发,或者使用成熟的第三方DDC/CI库简化流程。

内容的提问来源于stack exchange,提问作者fulano18

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:07:18