如何获取分辨率对话框中显示的实际显示器名称?

18

我试图获取系统监视器的友好名称,使用的语言是C#。

我已经尝试了Screen,它只给出了//./DisplayXX。我也尝试了Win32_DesktopMonitorEnumDisplayDevices,它们都给出了//./DisplayXXGeneric Monitor的变化,而我知道我的显示器名称是SyncMasterSM2333T

现在Windows知道这些监视器是什么,在设备和打印机窗口中以正确的名称显示它们,并在设置位置和分辨率的对话框中显示它们。

我应该从哪里获取这些名称?我已经查看了注册表,但无法找到它们,所以任何帮助都将是巨大的。

解决方案:

我遇到的问题是在第二次调用EnumDisplayDevices时,我再次将iDevNum设置为id,这意味着我试图从错误的位置获取数据,然后我替换为0,它完美地工作了,以下是代码:

    var device = new DISPLAY_DEVICE();
    device.cb = Marshal.SizeOf(device);
    try
    {
        for (uint id = 0; EnumDisplayDevices(null, id, ref device, 0); id++)
        { 
                Console.WriteLine(String.Format("{0}, {1}, {2}, {3}, {4}, {5}", id, device.DeviceName, device.DeviceString, device.StateFlags, device.DeviceID, device.DeviceKey));
                Console.WriteLine();
                device.cb = Marshal.SizeOf(device);

                EnumDisplayDevices(device.DeviceName, 0, ref device, 0);

                Console.WriteLine(String.Format("{0}, {1}, {2}, {3}, {4}, {5}", id, device.DeviceName, device.DeviceString, device.StateFlags, device.DeviceID, device.DeviceKey));
                device.cb = Marshal.SizeOf(device);

                device.cb = Marshal.SizeOf(device);
                return;
            }

        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(String.Format("{0}", ex.ToString()));
    }

看起来你无法访问http://stackoverflow.com/a/24375561/67824 - Ohad Schneider
1
@OhadSchneider,请看一下我的问题,我已经提供了一个解决方案,并且在那个项目中一直运行良好。 - JamesStuddart
答案就在这里: http://stackoverflow.com/questions/26404982/how-get-monitors-friendly-name-with-winapi - G.Y
https://github.com/r1me/delphi-monitorhelper - Gabriel
5个回答

25

仔细看!这就是你正在寻找的,现在你可以写 Screen.PrimaryScreen.DeviceFriendlyName() 来获取显示器设备的真实名称。
(没错,这就是分辨率对话框中所看到的相同名称)

虽然我加了一些个人风格来包装这段代码,但我并没有创建它的硬核部分, 因此我要感谢两位开发人员,一位是提供了C++基础知识的微软开发人员,另一位是将这些基础知识转化为C#代码的匿名开发人员。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Tools;

namespace ConsoleApplication35
{
    internal class Program
    {

        private static void Main()
        {

            Console.WriteLine(Screen.PrimaryScreen.DeviceFriendlyName());

            //output: ASUS MK241

            Console.ReadLine();
        }
    }
}

namespace Tools
{
    public static class ScreenInterrogatory
    {
        public const int ERROR_SUCCESS = 0;

        #region enums

        public enum QUERY_DEVICE_CONFIG_FLAGS : uint
        {
            QDC_ALL_PATHS = 0x00000001,
            QDC_ONLY_ACTIVE_PATHS = 0x00000002,
            QDC_DATABASE_CURRENT = 0x00000004
        }

        public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint
        {
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 0xFFFFFFFF,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000,
            DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint
        {
            DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
            DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
            DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
            DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
            DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
            DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_ROTATION : uint
        {
            DISPLAYCONFIG_ROTATION_IDENTITY = 1,
            DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
            DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
            DISPLAYCONFIG_ROTATION_ROTATE270 = 4,
            DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_SCALING : uint
        {
            DISPLAYCONFIG_SCALING_IDENTITY = 1,
            DISPLAYCONFIG_SCALING_CENTERED = 2,
            DISPLAYCONFIG_SCALING_STRETCHED = 3,
            DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
            DISPLAYCONFIG_SCALING_CUSTOM = 5,
            DISPLAYCONFIG_SCALING_PREFERRED = 128,
            DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_PIXELFORMAT : uint
        {
            DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
            DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
            DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
            DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
            DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
            DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff
        }

        public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint
        {
            DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
            DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
            DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF
        }

        public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint
        {
            DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
            DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
            DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
            DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
            DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
            DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
            DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF
        }

        #endregion

        #region structs

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public uint LowPart;
            public int HighPart;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_PATH_SOURCE_INFO
        {
            public LUID adapterId;
            public uint id;
            public uint modeInfoIdx;
            public uint statusFlags;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_PATH_TARGET_INFO
        {
            public LUID adapterId;
            public uint id;
            public uint modeInfoIdx;
            private DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
            private DISPLAYCONFIG_ROTATION rotation;
            private DISPLAYCONFIG_SCALING scaling;
            private DISPLAYCONFIG_RATIONAL refreshRate;
            private DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
            public bool targetAvailable;
            public uint statusFlags;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_RATIONAL
        {
            public uint Numerator;
            public uint Denominator;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_PATH_INFO
        {
            public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
            public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
            public uint flags;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_2DREGION
        {
            public uint cx;
            public uint cy;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
        {
            public ulong pixelRate;
            public DISPLAYCONFIG_RATIONAL hSyncFreq;
            public DISPLAYCONFIG_RATIONAL vSyncFreq;
            public DISPLAYCONFIG_2DREGION activeSize;
            public DISPLAYCONFIG_2DREGION totalSize;
            public uint videoStandard;
            public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_TARGET_MODE
        {
            public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINTL
        {
            private int x;
            private int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_SOURCE_MODE
        {
            public uint width;
            public uint height;
            public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
            public POINTL position;
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct DISPLAYCONFIG_MODE_INFO_UNION
        {
            [FieldOffset(0)]
            public DISPLAYCONFIG_TARGET_MODE targetMode;

            [FieldOffset(0)]
            public DISPLAYCONFIG_SOURCE_MODE sourceMode;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_MODE_INFO
        {
            public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
            public uint id;
            public LUID adapterId;
            public DISPLAYCONFIG_MODE_INFO_UNION modeInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
        {
            public uint value;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DISPLAYCONFIG_DEVICE_INFO_HEADER
        {
            public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
            public uint size;
            public LUID adapterId;
            public uint id;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct DISPLAYCONFIG_TARGET_DEVICE_NAME
        {
            public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
            public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
            public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
            public ushort edidManufactureId;
            public ushort edidProductCodeId;
            public uint connectorInstance;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string monitorFriendlyDeviceName;

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

        #endregion

        #region DLL-Imports

        [DllImport("user32.dll")]
        public static extern int GetDisplayConfigBufferSizes(
            QUERY_DEVICE_CONFIG_FLAGS flags, out uint numPathArrayElements, out uint numModeInfoArrayElements);

        [DllImport("user32.dll")]
        public static extern int QueryDisplayConfig(
            QUERY_DEVICE_CONFIG_FLAGS flags,
            ref uint numPathArrayElements, [Out] DISPLAYCONFIG_PATH_INFO[] PathInfoArray,
            ref uint numModeInfoArrayElements, [Out] DISPLAYCONFIG_MODE_INFO[] ModeInfoArray,
            IntPtr currentTopologyId
            );

        [DllImport("user32.dll")]
        public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName);

        #endregion

        private static string MonitorFriendlyName(LUID adapterId, uint targetId)
        {
            var deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME
            {
                header =
                {
                    size = (uint)Marshal.SizeOf(typeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)),
                    adapterId = adapterId,
                    id = targetId,
                    type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
                }
            };
            var error = DisplayConfigGetDeviceInfo(ref deviceName);
            if (error != ERROR_SUCCESS)
                throw new Win32Exception(error);
            return deviceName.monitorFriendlyDeviceName;
        }

        private static IEnumerable<string> GetAllMonitorsFriendlyNames()
        {
            uint pathCount, modeCount;
            var error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
            if (error != ERROR_SUCCESS)
                throw new Win32Exception(error);

            var displayPaths = new DISPLAYCONFIG_PATH_INFO[pathCount];
            var displayModes = new DISPLAYCONFIG_MODE_INFO[modeCount];
            error = QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS,
                ref pathCount, displayPaths, ref modeCount, displayModes, IntPtr.Zero);
            if (error != ERROR_SUCCESS)
                throw new Win32Exception(error);

            for (var i = 0; i < modeCount; i++)
                if (displayModes[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET)
                    yield return MonitorFriendlyName(displayModes[i].adapterId, displayModes[i].id);
        }

        public static string DeviceFriendlyName(this Screen screen)
        {
            var allFriendlyNames = GetAllMonitorsFriendlyNames();
            for (var index = 0; index < Screen.AllScreens.Length; index++)
                if (Equals(screen, Screen.AllScreens[index]))
                    return allFriendlyNames.ToArray()[index];
            return null;
        }

    }

}

1
谢谢,这正是我想要的 :) - jamie
伟大的答案成功地运作了。 唯一缺失的答案是查询前廊、同步和后廊的能力。我想找出一种查询完整视频信号定时信息的方法。 - Mark Rejhon
你的解决方案能否扩展并获得对角线尺寸?或者物理宽度和高度? - Puty
@Puty,你的意思是“物理”——以多少英寸为单位?不,我认为它在电子设备中不存在,只有像素计数可用。但是,你可以拥有一个包含所有型号等的长字典...但是...谁来维护它呢?如果你需要这些信息进行某些处理,我建议你让用户自己定义每个屏幕的信息。 - G.Y
@G.Y,我不需要知道屏幕的物理尺寸(以英寸为单位),但我需要找出每英寸的像素数(PPI)。我只需要物理尺寸来计算PPI。有没有办法找出所有连接显示器的PPI?现在我使用“WmiMonitorBasicDisplayParams”类,但属性“MaxHorizontalImageSize”和“MaxVerticalImageSize”仅为uint8,并且与设备的物理宽度和高度不完全匹配。 - Puty
对于那些想要C/C++版本的人,https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig#examples 是MS文档中的一个示例。 - Wez Furlong

16

当您从EnumDisplayDevices获得像//./DisplayX这样的DisplayDevice.DeviceName后,您应该第二次调用'EnumDisplayDevices'函数,这次将之前调用中获得的“DisplayDevice.DeviceName”作为lpDevice参数,将0作为iDevNum参数。然后您就能在DisplayDevice.DeviceString中获得显示器名称。


啊!我会去检查一下,我确实做了第二个调用,但是又在 DeviceName 下面找了一遍 ;) 谢谢,如果这样可以的话,我会标记为正确的。 - JamesStuddart
@James - 那个结果有些奇怪,你不应该得到这个或那个。每次调用时,你应该始终得到相同的字符串。顺便说一下,在“设备和打印机”视图中,我从未看到过监视器条目,这对我来说是新的。在“设备管理器”下的“显示器”下,这些名称与你所看到的名称相同吗? - Sertac Akyuz
1
当我说空的或通用的时候,我是指每个监视器,因为我在这台机器上有5个。在设备管理器中,它们都显示为通用 Pnp 监视器,除了 SyncMaster。 - JamesStuddart
1
有趣的是,这对我不起作用。它只给了我“通用 PnP 显示器”,而控制面板显示“SyncMaster”。 - Luke
我得到了与@luke相同的结果。它对所有显示器返回“通用PnP监视器”。 - elmindreda
显示剩余7条评论

5
这些信息几乎肯定是通过SetupAPI函数家族获取的。我不记得具体细节,但您需要获取所有监视器设备(GUID_DEVINTERFACE_MONITOR)并获取它们的友好名称(SPDRP_FRIENDLYNAME)。

我已经按照您的建议尝试,但无济于事。如果您能看一下这个链接就太好了:http://stackoverflow.com/questions/24356289/setupdigetdeviceregistryproperty-fails-with-error-invalid-data - Ohad Schneider

4

从这里开始: 获取准确的监视器/显示器/屏幕名称

嗯,这个问题很老了,不过为了谷歌重定向的缘故,我建议使用我的“WindowsDisplayAPI”库。

https://www.nuget.org/packages/WindowsDisplayAPI


使用该库,有多种方法可以获取显示名称。最简单的方法是:
foreach (var display in Display.GetDisplays())
{
    Console.WriteLine(display.DeviceName);
}

但是这是使用旧的API,如果你确定你的程序至少针对Windows Vista,我建议使用以下代码:

foreach (var target in DisplayConfig.PathDisplayTarget.GetDisplayTargets())
{
    Console.WriteLine(target.FriendlyName);
}

你应该明确说明你是作者。 - Ronnie W
@RonnieW,已完成。虽然这并不重要,但是GitHub项目页面和NuGet软件包页面都清楚地说明了这一点。 - Soroush Falahati
3
请注意,NuGet采用LGPL v3许可证。 - Yury Schkatula
@YurySchkatula,你把LGPL和GPL搞混了。 - Soroush Falahati

0

我一直在寻找这个同样问题的答案。在this link中提到显示了通用 Pnp 监视器,因为没有为监视器安装驱动程序,设备正在使用通用 PnP 监视器驱动程序。

对于 Windows 7 及更高版本,似乎有一个不同于 EnumDisplayDevices 的函数来获取控制面板中所显示的期望显示名称。可以通过 DisplayConfigGetDeviceInfo 函数完成,如here所述。我希望有人能够尽快将其翻译成 Delphi,这正是我所需要的。


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