获取显示器(主/副屏)友好名称(FriendlyName)

devtools/2024/12/23 9:04:31/

在开发涉及多显示器的应用程序时,获取显示器的友好名称(Friendly Name)是一个常见需求。本文将深入探讨GetMonitorFriendlyName 方法,了解其实现细节和工作原理。

方法签名

public static string GetMonitorFriendlyName(bool isPrimary)

方法概述

GetMonitorFriendlyName 方法用于获取指定显示器的友好名称。参数 isPrimary 指定是否获取主显示器的友好名称。

实现原理

  1. 先获取显示设备的目标设备信息和源设备信息,再将目标设备信息(友好名称)和源设备信息(逻辑设备名称)关联起来
  2. 获取要求获取屏幕(主/副屏)的信息(包含逻辑设备名称)
  3. 通过逻辑设备名称关联,再找到相应屏幕的友好名称

实现细节

1. 获取屏幕信息:

    var screen = ScreenHelper.GetScreen(isPrimary);

2. 获取目标设备名称:

    var targetDeviceNames = GeTargetDeviceNames();

调用 GeTargetDeviceNames 方法获取所有活动路径的目标设备名称和源设备名称。

3. 匹配屏幕设备名称:

    return targetDeviceNames.FirstOrDefault(m => m.Item2.viewGdiDeviceName.EqualsIgnoreCase(screen.DeviceName)).Item1.monitorDevicePath;

核心方法

GeTargetDeviceNames 方法: 该方法获取所有活动路径的目标设备名称和源设备名称,并将目标设备名称和源设备名称相匹配。其实现涉及调用 Windows API 函数 GetDisplayConfigBufferSizes 和 QueryDisplayConfig,并解析返回的显示配置信息。

/// <summary>
/// 获取显示器FriendlyName名称
/// </summary>
/// <returns></returns>public static IEnumerable<(DISPLAYCONFIG_TARGET_DEVICE_NAME, DISPLAYCONFIG_SOURCE_DEVICE_NAME)>GeTargetDeviceNames(){List<(DISPLAYCONFIG_TARGET_DEVICE_NAME, DISPLAYCONFIG_SOURCE_DEVICE_NAME)> listRet = new();try{int error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS,out var pathCount, out var modeCount);if (error != ERROR_SUCCESS)throw new Win32Exception(error);DISPLAYCONFIG_PATH_INFO[] DisplayPaths = new DISPLAYCONFIG_PATH_INFO[pathCount];DISPLAYCONFIG_MODE_INFO[] 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 (int i = 0; i < modeCount; i++){var modeInfo = DisplayModes[i];if (modeInfo.infoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET){var targetName =GetDisplayconfigTargetDeviceName(DisplayModes[i].adapterId, DisplayModes[i].id);var displayPathInfo = DisplayPaths.FirstOrDefault(m =>m.targetInfo.adapterId.LowPart == modeInfo.adapterId.LowPart &&m.targetInfo.adapterId.HighPart == modeInfo.adapterId.HighPart &&m.targetInfo.id == modeInfo.id);var sourceName = GetDisplayconfigSourceDeviceName(displayPathInfo.sourceInfo.adapterId,displayPathInfo.sourceInfo.id);listRet.Add((targetName, sourceName));}}}catch (Exception ex){}return listRet;}

相关辅助方法

  • GetDisplayconfigTargetDeviceName 方法:获取目标设备的详细信息,包括友好名称
  • GetDisplayconfigSourceDeviceName 方法: 获取源设备的详细信息,包括显示设备逻辑名称。
public const int ERROR_SUCCESS = 0;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
}[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;DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;DISPLAYCONFIG_ROTATION rotation;DISPLAYCONFIG_SCALING scaling;DISPLAYCONFIG_RATIONAL refreshRate;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
{int x;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;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public partial struct DISPLAYCONFIG_SOURCE_DEVICE_NAME
{public DISPLAYCONFIG_DEVICE_INFO_HEADER header;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string viewGdiDeviceName;
}
[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
);
[DllImport("user32.dll")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName
);
[DllImport("user32", CharSet = CharSet.Auto)]
public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
/// <summary>
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto,Pack=4)]
public struct MONITORINFO
{/// <summary>/// </summary>            public int cbSize;/// <summary>/// </summary>            public ScreenHelper.RECT rcMonitor;/// <summary>/// </summary>            public ScreenHelper.RECT rcWork;/// <summary>/// </summary>            public int dwFlags ;/*[MarshalAs(UnmanagedType.ByValArray, SizeConst=32)] public char[]  szDevice;*/[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string DeviceName;
}public static DISPLAYCONFIG_TARGET_DEVICE_NAME GetDisplayconfigTargetDeviceName(LUID adapterId, uint targetId)
{DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME();deviceName.header.size = (uint)Marshal.SizeOf(typeof(DISPLAYCONFIG_TARGET_DEVICE_NAME));deviceName.header.adapterId = adapterId;deviceName.header.id = targetId;deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;int error = DisplayConfigGetDeviceInfo(ref deviceName);if (error != ERROR_SUCCESS)throw new Win32Exception(error);return deviceName;
}public static DISPLAYCONFIG_SOURCE_DEVICE_NAME GetDisplayconfigSourceDeviceName(LUID adapterId, uint targetId)
{DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName = new DISPLAYCONFIG_SOURCE_DEVICE_NAME();deviceName.header.size = (uint)Marshal.SizeOf(typeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME));deviceName.header.adapterId = adapterId;deviceName.header.id = targetId;deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;int error = DisplayConfigGetDeviceInfo(ref deviceName);if (error != ERROR_SUCCESS)throw new Win32Exception(error);return deviceName;
}

示例代码

以下是 GetMonitorFriendlyName 方法的完整实现:

public static string GetMonitorFriendlyName(bool isPrimary)
{try{var screen = ScreenHelper.GetScreen(isPrimary);var targetDeviceNames = GeTargetDeviceNames();return targetDeviceNames.FirstOrDefault(m => m.Item2.viewGdiDeviceName.EqualsIgnoreCase(screen.DeviceName)).Item1.monitorDevicePath;}catch (Exception ex){return string.Empty;}
}

http://www.ppmy.cn/devtools/144645.html

相关文章

Debian 10上使用UFW设置防火墙

介绍 UFW或Uncomplicated Firewall是iptables一个接口&#xff0c;旨在简化配置防火墙的过程。 虽然iptables是一个可靠而灵活的工具&#xff0c;但初学者很难学会如何使用它来正确配置防火墙。 如果您希望开始保护网络并且不确定使用哪种工具&#xff0c;UFW可能是您的正确选…

构建全面的生产监控体系:从基础设施到业务服务

在现代 IT 系统中&#xff0c;监控体系是确保高可用性、高性能和稳定性的核心工具。一个完善的监控体系能够及时发现系统问题、分析问题根源并快速采取应对措施&#xff0c;避免故障进一步扩散。本文将从基础设施层、中间件层、容器与编排层、应用与服务层逐步展开&#xff0c;…

每天40分玩转Django:实操在线商城

实操在线商城 一、今日学习内容概述 模块重要程度主要内容商品模型⭐⭐⭐⭐⭐商品信息、分类管理购物车系统⭐⭐⭐⭐⭐购物车功能实现订单系统⭐⭐⭐⭐⭐订单处理、支付集成用户中心⭐⭐⭐⭐订单管理、个人信息 二、模型设计 # models.py from django.db import models fro…

CSS3 实现火焰-小火苗效果

创建 CSS3 火焰效果可以通过组合 CSS 动画、伪元素 和 渐变 来实现。以下是一个简单的实现步骤&#xff0c;展示如何制作动态火焰效果 1. HTML 结构 我们只需要一个简单的 div 容器&#xff1a; <div class"fire"></div>2. CSS 实现 基础样式 使用 …

vi或vim进行替换

vi 中去搜索特定字符串cdc_,替换为aaa_ 在 vi 或 vim 编辑器中&#xff0c;你可以使用以下命令来查找特定的字符串 cdc_ 并将其替换为 aaa_&#xff1a; 打开文件&#xff1a; vi filename 搜索 /cdc_ 按n 是搜索下一个 进入替换模式&#xff1a; :%s/cdc_/aaa_/g 解释&#…

CSS 第七章

B站《前端Web开发HTML5CSS3移动web视频教程》第九天和第10天的课程&#xff1a;SEO、Favicon、小兔鲜网页制作。 一、项目目录 1.根文件夹xtx-pc 2.子文件夹 images文件夹&#xff1a;存放固定使用的图片素材uploads文件夹&#xff1a;存放非固定使用的图片素材iconfont文件…

2024 高级爬虫笔记(四)协程、selenium

目录 一、协程1.1 概念1.2、asyncio模块1.2.1、概述1.2.2、asyncio基本使用1.2.3、使用协程实现多任务异步执行1.2.4、Task 概念及用法1.2.4.1 概念1.2.4.2、Task 简单用法 1.2.5、asyncio.wait和asyncio.gather的异同 1.3、aiohttp1.3.1、安装与使用1.3.2、简单使用1.3.3、在U…

uniapp 微信小程序 功能入口

单行单独展示 效果图 html <view class"shopchoose flex jsb ac" click"routerTo(要跳转的页面)"><view class"flex ac"><image src"/static/dyd.png" mode"aspectFit" class"shopchooseimg"&g…