Windows下提示显示器信息主要通过两个函数实现。一个是EnumDisplayDevices(), 另一个是EnumDisplayMonitors(). EnumDisplayDevices()枚举所有显示设备,而EnumDisplayMonitors枚举的是所有显示器。显示设备和显示器不一样,比如显卡算显示设备,但是不是显示器。具体差别后面会分析。EnumDisplayMonitors()还会枚举出不可见的伪显示器,如果只是想得到实际的显示器数目的话可以用GetSystemMetrics(SM_CMONITORS), 该函数不包括虚拟显示器。

下面一段代码展示了这三个函数的用法和差别(参考自https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/668e3cf9-4e00-4b40-a6f8-c7d2fc1afd39/how-can-i-retrieve-monitor-information?forum=windowsgeneraldevelopmentissues)

// MonitorSerialCtrlApp.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include <windows.h>
using namespace std;BOOL CALLBACK MyInfoEnumProc(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,LPARAM dwData
)
{MONITORINFOEX mi;ZeroMemory(&mi, sizeof(mi));mi.cbSize = sizeof(mi);GetMonitorInfo(hMonitor, &mi);wprintf(L"DisplayDevice: %s\n", mi.szDevice);return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{int numMonitor;int run=0;while(1){ printf("*********************%d****************\n",run);run++;printf("\n\n\EnumDisplayDevices\n\n\n");DISPLAY_DEVICE dd;ZeroMemory(&dd, sizeof(dd));dd.cb = sizeof(dd);for(int i=0; EnumDisplayDevices(NULL, i, &dd, 0); i++){//EnumDisplayDevices(NULL, i, &dd, 0);wprintf(L"\n\nDevice %d:", i);wprintf(L"\n    DeviceName:   '%s'", dd.DeviceName);wprintf(L"\n    DeviceString: '%s'", dd.DeviceString);wprintf(L"\n    StateFlags:   %s%s%s%s",((dd.StateFlags &DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ?L"desktop " : L""),((dd.StateFlags &DISPLAY_DEVICE_PRIMARY_DEVICE     ) ?L"primary " : L""),((dd.StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) ?L"vga "     : L""),((dd.StateFlags &DISPLAY_DEVICE_MULTI_DRIVER       ) ?L"multi "   : L""),((dd.StateFlags &DISPLAY_DEVICE_MIRRORING_DRIVER   ) ?L"mirror "  : L""));// Get more info about the deviceDISPLAY_DEVICE dd2;ZeroMemory(&dd2, sizeof(dd2));dd2.cb = sizeof(dd2);EnumDisplayDevices(dd.DeviceName, 0, &dd2, 0);wprintf(L"\n    DeviceID: '%s'", dd2.DeviceID);wprintf(L"\n    Monitor Name: '%s'", dd2.DeviceString);}printf("\n\n\nEnumDisplayMonitors\n\n\n");EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, 0);numMonitor = GetSystemMetrics(SM_CMONITORS);printf("GetSystemMetrics: %d\n", numMonitor);Sleep(5000);}while(1);return 0;
}

这段代码每5秒钟刷新一次显示器显示设备信息。输出结果如下:

*********************3***************EnumDisplayDevicesDevice 0:DeviceName:   '\\.\DISPLAY1'DeviceString: 'NVIDIA GeForce GTX 760'StateFlags:   desktop primaryDeviceID: 'MONITOR\ACI23F7\{4d36e96e-e325-11ce-bfc1-08002be10318}\0002'Monitor Name: 'Generic PnP Monitor'Device 1:DeviceName:   '\\.\DISPLAY2'DeviceString: 'NVIDIA GeForce GTX 760'StateFlags:   desktopDeviceID: 'MONITOR\ACI23F7\{4d36e96e-e325-11ce-bfc1-08002be10318}\0001'Monitor Name: 'Generic PnP Monitor'Device 2:DeviceName:   '\\.\DISPLAY3'DeviceString: 'NVIDIA GeForce GTX 760'StateFlags:   desktopDeviceID: 'MONITOR\GSM0001\{4d36e96e-e325-11ce-bfc1-08002be10318}\0003'Monitor Name: 'Generic PnP Monitor'Device 3:DeviceName:   '\\.\DISPLAY4'DeviceString: 'NVIDIA GeForce GTX 760'StateFlags:DeviceID: ''Monitor Name: ''Device 4:DeviceName:   '\\.\DISPLAYV1'DeviceString: 'RDPDD Chained DD'StateFlags:DeviceID: ''Monitor Name: ''Device 5:DeviceName:   '\\.\DISPLAYV2'DeviceString: 'RDP Encoder Mirror Driver'StateFlags:DeviceID: ''Monitor Name: ''Device 6:DeviceName:   '\\.\DISPLAYV3'DeviceString: 'RDP Reflector Display Driver'StateFlags:DeviceID: ''Monitor Name: ''EnumDisplayMonitorsDisplayDevice: \\.\DISPLAY1
DisplayDevice: \\.\DISPLAY2
DisplayDevice: \\.\DISPLAY3
GetSystemMetrics: 3

可以看出EnumDisplayDevices()列出的都是显示设备。前四个都是我的显卡 GeforceGTX 760. 有4个设备因为我的显卡有4个接口。其中前三个接口接了显示器,所以下面显示了显示器信息。显示器名都是”通用即插即用显示器”这和windows设备管理器里显示的名字是一样的。唯一能有区分度的信息是DeviceID里MONITOR\后面的7个字符,这7个字符是和生产厂商信号相关的。ACI23F7代表的我的ASUS显示器,GSM001指的是LG显示器。值得注意的是Windows7显示属性里或控制面板硬件里能显示出显示器可识别的显示器型号和厂商,这个信息想通过编程方法获得是不可能的,这点已经在该网页留言里由微软工作人员验证了。原话是“Thereis not a supported way to figour out the IDs that you referred toprogrammatically. It was never a design goal to provide a way for applicationsto label monitors with the same IDs that the screen resolution control paneluses.”

EnumDisplayMonitors()只会列出显示器信息。如上,显示的是

DisplayDevice: \\.\DISPLAY1

DisplayDevice: \\.\DISPLAY2

DisplayDevice: \\.\DISPLAY3

GetSystemMetrics (SM_CMONITORS) 只会得到显示器个数:3

值得一提的是,实验发现,当所有显示器都拔掉后,Nvidia会自己虚拟一个显示器NVD0000,所以没有显示器时,使用GetSystemMetrics(SM_CMONITORS)得到的显示器个数是1

如上函数只能轮询获得当前显示器信息,如何能检测显示器插拔呢?

有设备变化时Windows会发出WM_DEVICECHANGE的信息。但是默认情况下Windows发出WM_DEVICECHANGE有两个条件:

1.      程序必须有个主窗口

2.      得是端口和磁盘变化才行

要检测别的硬件插拔,或者该程序没有主窗口,则必须使用RegisterDeviceNotification() 函数注册所需监视的硬件。微软官方给了个使用该函数的范例:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx

该范例中,所需监测的设备类型是通过GUID的函数参数传递给系统的。

// This GUID is for all USB serial host PnP drivers, but you can replace it
// with any valid device class guid.
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };

需要注意的是改GUID必须是个设备接口GUID。有两种GUID,一个是设备类型GUID(device  class GUID),另一个是设备接口GUID(device interfaceGUID)。设备类型GUID决定了在设备管理器里设备是哪一种类型。设备接口GUID是与设备与系统的接口相关的,这才是我们需要传递的参数。设备接口GUID可以在微软官方上查询得到。这里(https://msdn.microsoft.com/en-us/library/windows/hardware/ff545901(v=vs.85).aspx)查询到显示器的接口GUID是{E6F07B5F-EE97-4a90-B076-33F57BF4EAA7},替换至范例代码里就能检测到显示器插拔了。。。运行结果如下:

DBT_DEVICEREMOVECOMPLETE 代表硬件移除

DBT_DEVNODES_CHANGED 代表硬件变化,插入移除都会有该消息

DBT_DEVICEARRIVAL代表硬件插入

之后再在DBT_DEVICEARRIVAL信息后面查询DEV_BROADCAST_DEVICEINTERFACE结构体里的dbcc_name成员就可以得到新插入的显示器信息。

        PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE) lParam;TCHAR strBuff[256];TCHAR deviceID[8];TCHAR *ptr;// Output some messages to the window.switch (wParam){case DBT_DEVICEARRIVAL:msgCount++;StringCchPrintf(strBuff, 256, TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount);wcscat_s(strBuff, b->dbcc_name);wcscat_s(strBuff, TEXT("\n"));break;case DBT_DEVICEREMOVECOMPLETE:
.
.
.
.

运行结果如下

GSM0001代表新插入的是LG显示器。

参考:

http://www.codeproject.com/Articles/14500/Detecting-Hardware-Insertion-and-or-Removal

(转载请注明)

Windows 下编程检测显示器信息及插拔相关推荐

  1. windows下编程控制摄像头的详细介绍

    这段时间闲来无事,看了看MSDN的文档,自己翻译了一下.一是为了学习,二是对空闲时间的打发.所以也希望大家在拍砖的同时,尊重我的劳动,如要转贴请注明转至blog.csdn.net/suntaoznz. ...

  2. Windows 下 Quartus 检测不到 USB-Blaster 终极解决办法

    Windows 下 Quartus 检测不到 USB-Blaster 终极解决办法 转自https://blog.csdn.net/acang301/article/details/50471067? ...

  3. Windows下编程--模拟时钟的实现

    windows下编程--模拟时钟的实现: 主要可以分为几个步骤: (1)   编写按键事件处理(启动和停止时钟) (2)   编写时钟事件处理,调用显示时钟函数 (3)   编写显示时钟函数,要调用显 ...

  4. 在Linux下编程和在Windows下编程的区别

    Linux和Windows是两种操作系统,从用户群来说Linux是一个以开发者为中心的操作系统,而windows是以消费者为中心的操作系统,这也是两个操作系统作为根本的区别. 在Linux与Windo ...

  5. Windows 下查看系统硬件信息

    Windows 下查看系统硬件信息 本文转载自https://blog.csdn.net/guyan1101/article/details/86706859 一.如何在windows系统自带命令查看 ...

  6. 快捷键实现MAC或者WINDOWS下快速切换显示器输入源

    目录 通过键盘实现mac或者Windows显示器输入信号源快捷键切换(电脑怎么切换屏幕的信号输入) 前言 一.通过显示器菜单按钮控制 二.通过快捷键设置 1.window系统 对ControlMyMo ...

  7. Windows下编程需要看哪些书

    本人是自学计算机的,所有计算机方面的知识都看,研究过一段时间网络,对计算机网络方面有一定的基础,对程序设计尤感兴趣,个人认为学习Windows编程需要有以下基础: 1.C语言 这方面不用说清华大学谭浩 ...

  8. 从 dig(nslookup) bind —— windows 下的域名解析服务器信息的查看

    dig(domain information groper,之所以选择这三个词,在于这三个词的首字母构成的词 dig 也有探索挖掘的含义)本身是 Linux 下的查询 DNS 信息的工具,功能类似 n ...

  9. 005.在Windows下编程让效率起飞

    不少朋友一开始在Linux下用vim肯定是会像博主一样痛苦,vim没有智能提示,有的函数参数又臭又长初学者根本就记不住,而且有时候写代码没有智能提示,就会感到非常的挫败,还好vs2019已经直接支持远 ...

最新文章

  1. XML 命名空间概述
  2. 内存和外存的主要区别_内存与外存的关键区别有哪些?
  3. Python与C之间的相互调用
  4. MongoDB数据量大于2亿后遇到的问题 及原因分析
  5. php将中文编译成字符串,PHP将汉字字符串转换为数组
  6. 用户体验的13条金科玉律
  7. char强制类型转换为int_数据类型专题之三: char类型和类型转换
  8. 字符串逆序(三种方法)
  9. firefox 各个版本都在这里
  10. mysql.sock介绍
  11. shader拖尾_u3d拖尾特效组件-------TrailRenderer
  12. java 点名器_java随机点名器 课程设计.docx
  13. Striped64 api详解
  14. 如何用蓝牙网关广播蓝牙数据
  15. html 数据交互动画,纯css实现可交互的动画
  16. 大数据未来发展怎么样?
  17. Linux 下安装 oracle 19c(linux版本 centos 7)
  18. 应用在hiapk安卓市场分类排行榜中不显示的原因
  19. 赠书 | DeFi沉思录:历史、中国与未来
  20. “I don’t understand” 表达 “我不明白”,太老土了!

热门文章

  1. 工业智能网关BL110应用之45:实现欧姆龙 PLC CJ/CS/CP 接入华为云平台
  2. 洛谷P1034矩形覆盖题解--zhengjun
  3. 软考高项论文范文——论信息系统项目的采购管理
  4. 经典逗女孩子的暴笑短信
  5. 汉诺塔游戏《算法很美》
  6. Python实现微信接收消息推送(附源码)
  7. 《人民的名义》之陆毅的演技
  8. 【12月比赛合集】42场可报名的数据挖掘奖金赛,任君挑选!
  9. 已解决(Python读取xml文件报错)xmL.etree.ELementTree.ParseError:not well-formed (invalid token): Line
  10. 零基础抖音电商主播培训计划直播脚本话术大全范文ppt模板