Skip to content

Instantly share code, notes, and snippets.

@vsetka
Last active November 6, 2017 11:54
Show Gist options
  • Save vsetka/a73a9f623c27a6592ca4d0d508b1125f to your computer and use it in GitHub Desktop.
Save vsetka/a73a9f623c27a6592ca4d0d508b1125f to your computer and use it in GitHub Desktop.
Get the Display device info (physical monitor size) from SetupAPI EDID
#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;
}
#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