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

Windows中EnumDisplayDevices不返回非活动显示器,如何检测失效显示器?

解决非活动显示器检测问题

方法一:修改EnumDisplayDevices的调用参数

EnumDisplayDevices默认仅返回活动状态的显示设备,要获取所有设备(包括非活动的),需在调用时传入EDD_ALL_DEVICES(值为0x00000002)作为第四个参数。

修改你的代码如下:

const uint EDD_ALL_DEVICES = 0x00000002;
const uint DISPLAY_DEVICE_ACTIVE = 0x00000001;

DISPLAY_DEVICEW adapter = new DISPLAY_DEVICEW();
adapter.cb = Marshal.SizeOf(adapter);

uint deviceNum = 0;
while (EnumDisplayDevicesW(null, deviceNum, ref adapter, EDD_ALL_DEVICES))
{
    Console.WriteLine("适配器名称: " + adapter.DeviceName);
    Console.WriteLine("设备状态: " + ((adapter.StateFlags & DISPLAY_DEVICE_ACTIVE) != 0 ? "活动" : "非活动"));

    DISPLAY_DEVICEW display = new DISPLAY_DEVICEW();
    display.cb = Marshal.SizeOf(display);

    uint monitorNum = 0;
    while (EnumDisplayDevicesW(adapter.DeviceName, monitorNum, ref display, EDD_ALL_DEVICES))
    {
        Console.WriteLine("显示器名称: " + display.DeviceName);
        Console.WriteLine("显示器状态: " + ((display.StateFlags & DISPLAY_DEVICE_ACTIVE) != 0 ? "活动" : "非活动"));
        monitorNum++;
    }
    deviceNum++;
    Console.WriteLine("-------------------------------------");
}

方法二:使用SetupAPI枚举所有显示设备

对于USB集线器连接的显示器,部分非活动设备可能无法通过EnumDisplayDevices枚举到,这时可以用SetupAPI直接枚举系统中所有显示类设备,不受驱动激活状态影响。

示例代码:

using System;
using System.Runtime.InteropServices;

public class SetupApiDisplayEnumerator
{
    private const uint DIGCF_PRESENT = 0x00000002;
    private const uint DIGCF_DEVICEINTERFACE = 0x00000010;
    private const int SPDRP_FRIENDLYNAME = 0x0000000C;

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVICE_INTERFACE_DATA
    {
        public int cbSize;
        public Guid interfaceClassGuid;
        public int flags;
        public IntPtr reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVINFO_DATA
    {
        public int cbSize;
        public Guid classGuid;
        public uint devInst;
        public IntPtr reserved;
    }

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern IntPtr SetupDiGetClassDevs(ref Guid classGuid, IntPtr enumerator, IntPtr hwndParent, uint flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern bool SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfoData, ref Guid interfaceClassGuid, uint memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr hDevInfo, ref SP_DEVINFO_DATA devInfoData, uint property, out uint propertyRegDataType, IntPtr propertyBuffer, uint propertyBufferSize, out uint requiredSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, uint deviceInterfaceDetailDataSize, out uint requiredSize, ref SP_DEVINFO_DATA devInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern bool SetupDiDestroyDeviceInfoList(IntPtr hDevInfo);

    private static readonly Guid GUID_DEVINTERFACE_MONITOR = new Guid("{E6F07B5F-EE97-4a90-B076-33F57BF4EAA7}");

    public static void EnumerateAllMonitors()
    {
        IntPtr hDevInfo = SetupDiGetClassDevs(ref GUID_DEVINTERFACE_MONITOR, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
        if (hDevInfo == IntPtr.Zero)
        {
            Console.WriteLine("获取设备列表失败");
            return;
        }

        try
        {
            SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
            deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData);

            uint index = 0;
            while (SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref GUID_DEVINTERFACE_MONITOR, index, ref deviceInterfaceData))
            {
                SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA();
                devInfoData.cbSize = Marshal.SizeOf(devInfoData);

                uint requiredSize = 0;
                SetupDiGetDeviceInterfaceDetail(hDevInfo, ref deviceInterfaceData, IntPtr.Zero, 0, out requiredSize, ref devInfoData);

                IntPtr detailDataPtr = Marshal.AllocHGlobal((int)requiredSize);
                Marshal.WriteInt32(detailDataPtr, (IntPtr.Size == 4) ? 4 + Marshal.SystemDefaultCharSize : 8);

                if (SetupDiGetDeviceInterfaceDetail(hDevInfo, ref deviceInterfaceData, detailDataPtr, requiredSize, out requiredSize, ref devInfoData))
                {
                    string devicePath = Marshal.PtrToStringUni(IntPtr.Add(detailDataPtr, (IntPtr.Size == 4) ? 4 : 8));
                    Console.WriteLine("设备路径: " + devicePath);

                    uint regDataType;
                    uint bufferSize = 256;
                    IntPtr friendlyNameBuffer = Marshal.AllocHGlobal((int)bufferSize);
                    if (SetupDiGetDeviceRegistryProperty(hDevInfo, ref devInfoData, SPDRP_FRIENDLYNAME, out regDataType, friendlyNameBuffer, bufferSize, out requiredSize))
                    {
                        string friendlyName = Marshal.PtrToStringUni(friendlyNameBuffer);
                        Console.WriteLine("显示器名称: " + friendlyName);
                    }
                    Marshal.FreeHGlobal(friendlyNameBuffer);
                }
                Marshal.FreeHGlobal(detailDataPtr);

                index++;
                Console.WriteLine("-------------------------------------");
            }
        }
        finally
        {
            SetupDiDestroyDeviceInfoList(hDevInfo);
        }
    }
}

调用方式:

SetupApiDisplayEnumerator.EnumerateAllMonitors();

关键说明

  • EDD_ALL_DEVICES标志是让EnumDisplayDevices返回所有设备的核心,默认传入0仅返回活动设备
  • USB显示器属于复合硬件设备,SetupAPI能从底层枚举所有连接的显示器,不受显示驱动激活状态限制

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:50:27