C++ 获取多显示器设备信息

思路:

  1. 通过EnumDisplayMonitors枚举所有的显示器
  2. 通过GetMonitorInfo获取设备分辨率
  3. 通过EnumDisplaySettings获取设备刷新频率
  4. 通过EnumDisplayDevices获取edid数据在注册表中的位置
  5. 解析edid获取设备尺寸,厂商,名称等信息
  6. 通过CreateDC获取指定屏幕的HDC

edit参考:EDID标准简介EDID的简介和解析

下面是实现代码:

typedef struct stMonitorInfo
{
	TCHAR szfirm[4];//厂商
	TCHAR szname[18];//显示器名称
	unsigned long resolution_width, resolution_heght;//分辨率
	unsigned long device_width_cm, device_heght_cm;//设备尺寸
	unsigned long frequency;//设备刷新频率
	stMonitorInfo()
	{
		memset(this, 0, sizeof(stMonitorInfo));
	}
}stMonitorInfo;

枚举设备并且获取设备信息

	BOOL CALLBACK _MonitorEnumProc(HMONITOR hMonitor,  // handle to display monitor
		HDC hdcMonitor,     // handle to monitor DC
		LPRECT lprcMonitor, // monitor intersection rectangle
		LPARAM dwData       // data
		)
	{
		std::vector<stMonitorInfo> *pvec_monitor = (std::vector<stMonitorInfo>*) dwData;

		
		MONITORINFOEX miex;
		miex.cbSize = sizeof(miex);
		if (GetMonitorInfo(hMonitor, &miex))
		{
			stMonitorInfo monitor_info;
			monitor_info.resolution_width = miex.rcMonitor.right - miex.rcMonitor.left;
			monitor_info.resolution_heght = miex.rcMonitor.bottom - miex.rcMonitor.top;

			//monitor_info.device_millimeters_width = GetDeviceCaps(hdcMonitor, HORZSIZE);
			//monitor_info.device_millimeters_heght = GetDeviceCaps(hdcMonitor, VERTSIZE);

			

			DEVMODE devMode = { 0 };
			devMode.dmSize = sizeof(devMode);
			devMode.dmDriverExtra = sizeof(0);
			if (EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &devMode))
			{
				if (devMode.dmFields & DM_DISPLAYFREQUENCY)
				{
					monitor_info.frequency = devMode.dmDisplayFrequency;
				}
			}

			//为了防止edid不对,采取HDC方式获取
			HDC hdc = CreateDC(NULL, miex.szDevice, NULL, NULL);
			if (hdc)
			{
				get_display_physical_size(hdc, monitor_info.device_width_cm, monitor_info.device_heght_cm);
				DeleteDC(hdc);
			}
				

			DISPLAY_DEVICE data = { 0 };
			data.cb = sizeof(data);
			if (EnumDisplayDevices(miex.szDevice, 0, &data, EDD_GET_DEVICE_INTERFACE_NAME))
			{
				//DeviceID "\\\\?\\DISPLAY#DELA07A#5&30f41049&0&UID4352#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"	char[128]
				//开始解析
				printf("Monitor DeviceID:%s\r\n", data.DeviceID);
				std::vector<std::string> vec_data;
				split(data.DeviceID, "#", vec_data);
				if (vec_data.size() >= 3)
				{
					char szKey[1024] = "";
					_stprintf_s(szKey, 1024, "SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\%s\\%s\\Device Parameters", vec_data[1].c_str(), vec_data[2].c_str());
					
					std::vector<BYTE> edid;
					if (Registry::Read(HKEY_LOCAL_MACHINE, szKey, "EDID", edid))
					{
						//这里应该计算校验和如果校验和不对则忽略
						if (monitor_info.device_width_cm == 0 && monitor_info.device_heght_cm == 0)
						{
							monitor_info.device_width_cm = edid[0x15];
							monitor_info.device_heght_cm = edid[0x16];
						}
						
						//给一个默认名称,方式edid数据里面没有名称
						lstrcpyn(monitor_info.szname, vec_data[1].c_str(), 260);
						//避免大小端问题
						std::bitset<8> bits0(edid[8]);
						std::bitset<8> bits1(edid[9]);
						std::string strBits = bits0.to_string() + bits1.to_string();
						std::bitset<5> prd0(strBits, 1);
						std::bitset<5> prd1(strBits, 6);
						std::bitset<5> prd2(strBits, 11);
						ULONG lval0 = prd0.to_ulong();
						ULONG lval1 = prd1.to_ulong();
						ULONG lval2 = prd2.to_ulong();

						monitor_info.szfirm[0] = TCHAR('A') + lval0 - 1;
						monitor_info.szfirm[1] = TCHAR('A') + lval1 - 1;
						monitor_info.szfirm[2] = TCHAR('A') + lval2 - 1;
						
						//获取显示器名称
						std::vector<int> vec = { 0x36, 0x48, 0x5a, 0x6c };
						for (int i = 0; i < vec.size(); ++i)
						{
							
							int nindex = vec[i];
							if (edid[nindex] == 0x00 && edid[nindex + 1] == 0x00 && edid[nindex + 2] == 0x00 && edid[nindex +3] == 0xfc)
							{
								std::string str((char *)&edid[nindex + 4], 14);
								//删除\0 \n 0x20
								if (str[0] == 0) str = str.substr(1);
								while (!str.empty())
								{
									if (str[str.size() - 1] == 0x20 || str[str.size() - 1] == '\n')
									{
										str = str.substr(0, str.size() - 1);
										continue;
									}
									break;										
								}
								lstrcpy(monitor_info.szname, str.c_str());
							}
						}
					}
				}
				
			}
			pvec_monitor->push_back(monitor_info);
		}
		return TRUE;
	}

	void get_monitor_info(std::vector<stMonitorInfo> &vec_monitor)
	{
		EnumDisplayMonitors(NULL, NULL, _MonitorEnumProc, (LPARAM)&vec_monitor);
	}
	void get_display_resolution(int &width, int &height)
	{
		static int Width{ GetSystemMetrics(SM_CXSCREEN) };
		static int Heigth{ GetSystemMetrics(SM_CYSCREEN) };
		width = Width;
		height = Heigth;
	}

	void get_display_physical_size(HDC hdc,unsigned int &width_millimeters, unsigned int &height_millimeters)
	{
		bool bRelease = false;
		if (hdc == NULL)
		{
			bRelease = true;
			hdc = GetDC(NULL);
		}
		
		width_millimeters = GetDeviceCaps(hdc, HORZSIZE)/10;
		height_millimeters = GetDeviceCaps(hdc, VERTSIZE)/10;
		if (bRelease)
			ReleaseDC(NULL, hdc);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值