Last active
November 6, 2017 11:54
-
-
Save vsetka/a73a9f623c27a6592ca4d0d508b1125f to your computer and use it in GitHub Desktop.
Get the Display device info (physical monitor size) from SetupAPI EDID
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "DisplayDeviceHelper.h" | |
#include <sstream> | |
std::string ws2s(const std::wstring& s) | |
{ | |
int len; | |
int slength = (int)s.length() + 1; | |
len = WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, 0, 0, 0, 0); | |
char* buf = new char[len]; | |
WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, buf, len, 0, 0); | |
std::string r(buf); | |
delete[] buf; | |
return r; | |
} | |
DisplayDeviceHelper::DisplayDeviceHelper(const char * pDeviceName) | |
{ | |
m_deviceName = pDeviceName; | |
} | |
DisplayDeviceHelper::~DisplayDeviceHelper(void) | |
{ | |
} | |
bool DisplayDeviceHelper::ConvertLpwstrToStandardString(std::string& standardString, const LPWSTR stringToConvert) | |
{ | |
UINT codepage = CP_ACP; | |
bool res = false; | |
char* p = 0; | |
int bsz; | |
bsz = WideCharToMultiByte(codepage, 0, stringToConvert, -1, 0, 0, 0, 0); | |
if (bsz > 0) | |
{ | |
p = new char[bsz]; | |
int rc = WideCharToMultiByte(codepage, 0, stringToConvert,-1, p,bsz, 0, 0); | |
if (rc != 0) | |
{ | |
p[bsz-1] = 0; | |
standardString = p; | |
res = true; | |
} | |
} | |
delete [] p; | |
return res; | |
} | |
// Assumes hDevRegKey is valid | |
bool DisplayDeviceHelper::GetMonitorSizeFromEDID(const HKEY hDevRegKey, short& WidthMm, short& HeightMm) | |
{ | |
DWORD dwType, AcutalValueNameLength = NAME_SIZE; | |
WCHAR valueName[NAME_SIZE]; | |
std::string converted = ""; | |
std::string edid = "EDID"; | |
BYTE EDIDdata[1024]; | |
DWORD edidsize=sizeof(EDIDdata); | |
for (LONG i = 0, retValue = ERROR_SUCCESS; retValue != ERROR_NO_MORE_ITEMS; ++i) | |
{ | |
retValue = RegEnumValue ( hDevRegKey, i, &valueName[0], | |
&AcutalValueNameLength, NULL, &dwType, | |
EDIDdata, // buffer | |
&edidsize); // buffer size | |
ConvertLpwstrToStandardString(converted, valueName); | |
if (retValue != ERROR_SUCCESS || 0 != strcmp(converted.c_str(), edid.c_str())) | |
continue; | |
/*if (retValue != ERROR_SUCCESS || 0 != _tcscmp(valueName,_T("EDID"))) | |
continue;*/ | |
int byte66 = EDIDdata[66]; | |
int byte67 = EDIDdata[67]; | |
int byte68 = EDIDdata[68]; | |
int hiBits = (EDIDdata[68] & 0xF0); | |
int loBits = (EDIDdata[68] & 0x0F); | |
int hiBitsShifted = hiBits << 4; | |
int loBitsShifted = loBits << 8; | |
std::stringstream edidDebug; | |
edidDebug << "byte66 = " << byte66 << std::endl | |
<< "byte67 = " << byte67 << std::endl | |
<< "byte68 = " << byte68 << std::endl | |
<< "hiBits = " << hiBits << std::endl | |
<< "loBits = " << loBits << std::endl | |
<< "hiBitsShifted = " << hiBitsShifted << std::endl | |
<< "loBitsShifted = " << loBitsShifted << std::endl | |
<< "hiBitsShifted + byte66 = " << hiBitsShifted + byte66 << std::endl | |
<< "loBitsShifted + byte67 = " << loBitsShifted + byte67; | |
//MessageBoxA(NULL, edidDebug.str().c_str(), "Bytes", 0); | |
WidthMm = EDIDdata[21]; | |
HeightMm = EDIDdata[22]; | |
if (WidthMm <= 0 || HeightMm <= 0) | |
{ | |
WidthMm = ((EDIDdata[68] & 0xF0) << 4) + EDIDdata[66]; | |
HeightMm = ((EDIDdata[68] & 0x0F) << 8) + EDIDdata[67]; | |
} | |
else | |
{ | |
WidthMm *= 10; | |
HeightMm *= 10; | |
} | |
return true; // valid EDID found | |
} | |
return false; // EDID not found | |
} | |
std::wstring DisplayDeviceHelper::GetKeyPathFromHKEY(HKEY key) | |
{ | |
std::wstring keyPath; | |
if (key != NULL) | |
{ | |
HMODULE dll = LoadLibrary(L"ntdll.dll"); | |
if (dll != NULL) { | |
typedef DWORD (__stdcall *NtQueryKeyType)( | |
HANDLE KeyHandle, | |
int KeyInformationClass, | |
PVOID KeyInformation, | |
ULONG Length, | |
PULONG ResultLength); | |
NtQueryKeyType func = reinterpret_cast<NtQueryKeyType>(::GetProcAddress(dll, "NtQueryKey")); | |
if (func != NULL) { | |
DWORD size = 0; | |
DWORD result = 0; | |
result = func(key, 3, 0, 0, &size); | |
if (result == STATUS_BUFFER_TOO_SMALL) | |
{ | |
size = size + 2; | |
wchar_t* buffer = new (std::nothrow) wchar_t[size/sizeof(wchar_t)]; // size is in bytes | |
if (buffer != NULL) | |
{ | |
result = func(key, 3, buffer, size, &size); | |
if (result == STATUS_SUCCESS) | |
{ | |
buffer[size / sizeof(wchar_t)] = L'\0'; | |
keyPath = std::wstring(buffer + 2); | |
} | |
delete[] buffer; | |
} | |
} | |
} | |
FreeLibrary(dll); | |
} | |
} | |
return keyPath; | |
} | |
bool DisplayDeviceHelper::GetSizeForDevID(const std::string& TargetDevID, short& WidthMm, short& HeightMm) | |
{ | |
HDEVINFO devInfo = SetupDiGetClassDevsEx( | |
&GUID_CLASS_MONITOR, //class GUID | |
NULL, //enumerator | |
NULL, //HWND | |
DIGCF_PRESENT, // Flags //DIGCF_ALLCLASSES| | |
NULL, // device info, create a new one. | |
NULL, // machine name, local machine | |
NULL);// reserved | |
if (NULL == devInfo) | |
return false; | |
bool bRes = false; | |
for (ULONG i=0; ERROR_NO_MORE_ITEMS != GetLastError(); ++i) | |
{ | |
SP_DEVINFO_DATA devInfoData; | |
memset(&devInfoData,0,sizeof(devInfoData)); | |
devInfoData.cbSize = sizeof(devInfoData); | |
if (SetupDiEnumDeviceInfo(devInfo,i,&devInfoData)) | |
{ | |
HKEY hDevRegKey = SetupDiOpenDevRegKey(devInfo,&devInfoData, | |
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); | |
if(!hDevRegKey || (hDevRegKey == INVALID_HANDLE_VALUE)) | |
continue; | |
std::wstring fullRegistryKey = GetKeyPathFromHKEY(hDevRegKey); // TODO: Find a better way to compare against DeviceID | |
if (fullRegistryKey.find(std::wstring(TargetDevID.begin(), TargetDevID.end())) != std::wstring::npos) | |
{ | |
//MessageBoxW(NULL, fullRegistryKey.c_str(), L"Regkey", 0); | |
bRes = GetMonitorSizeFromEDID(hDevRegKey, WidthMm, HeightMm); | |
} | |
RegCloseKey(hDevRegKey); | |
if (bRes) | |
break; | |
} | |
} | |
SetupDiDestroyDeviceInfoList(devInfo); | |
return bRes; | |
} | |
bool DisplayDeviceHelper::GetMonitorSizeInCm(float &pWidth, float &pHeight) | |
{ | |
short WidthMm, HeightMm; | |
bool deviceFound = false; | |
DISPLAY_DEVICE dd; | |
dd.cb = sizeof(dd); | |
DWORD dev = 0; // device index | |
int id = 1; // monitor number, as used by Display Properties > Settings | |
std::string DeviceID; | |
bool bFoundDevice = false; | |
while (EnumDisplayDevices(0, dev, &dd, 0) && !bFoundDevice) | |
{ | |
DISPLAY_DEVICE ddMon; | |
ZeroMemory(&ddMon, sizeof(ddMon)); | |
ddMon.cb = sizeof(ddMon); | |
DWORD devMon = 0; | |
if (m_deviceName == ws2s(std::wstring(dd.DeviceName))) | |
{ | |
while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0) && !bFoundDevice) | |
{ | |
if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE && !(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) | |
{ | |
ConvertLpwstrToStandardString(DeviceID, ddMon.DeviceID); | |
DeviceID = DeviceID.substr(8, DeviceID.find('\\', 9) - 8); | |
bFoundDevice = GetSizeForDevID(DeviceID, WidthMm, HeightMm); | |
deviceFound = bFoundDevice; | |
} | |
devMon++; | |
ZeroMemory(&ddMon, sizeof(ddMon)); | |
ddMon.cb = sizeof(ddMon); | |
} | |
} | |
ZeroMemory(&dd, sizeof(dd)); | |
dd.cb = sizeof(dd); | |
dev++; | |
} | |
pWidth = (float)WidthMm / 10; | |
pHeight = (float)HeightMm / 10; | |
return deviceFound; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <windows.h> | |
#include <setupapi.h> | |
#include <devguid.h> | |
#include <regstr.h> | |
#include <string> | |
#include <iostream> | |
#ifdef UserMonitorCore_EXPORTS | |
#define SYMBOL_DECLSPEC __declspec(dllexport) | |
#else | |
#define SYMBOL_DECLSPEC __declspec(dllimport) | |
#endif | |
#define NAME_SIZE 128 | |
#define DISPLAY_DEVICE_ACTIVE 0x00000001 | |
#define STATUS_BUFFER_TOO_SMALL 0xC0000023 | |
#define STATUS_SUCCESS 0x00000000 | |
const GUID GUID_CLASS_MONITOR = {0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}; | |
class SYMBOL_DECLSPEC DisplayDeviceHelper | |
{ | |
public: | |
DisplayDeviceHelper(const char * pDeviceName); | |
~DisplayDeviceHelper(void); | |
bool DisplayDeviceHelper::GetMonitorSizeInCm(float &pWidth, float &pHeight); | |
private: | |
std::string m_deviceName; | |
bool GetSizeForDevID(const std::string& TargetDevID, short& WidthMm, short& HeightMm); | |
bool GetMonitorSizeFromEDID(const HKEY hDevRegKey, short& WidthMm, short& HeightMm); | |
bool ConvertLpwstrToStandardString(std::string& standardString, const LPWSTR stringToConvert); | |
std::wstring GetKeyPathFromHKEY(HKEY key); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment