EDID是显示器的fireware资料,保存有显示器大小信息,可以根据显示屏分辨率计算PPI,以适应合适的字体大小。

相关资料如下:

https://ofekshilon.com/2011/11/13/reading-monitor-physical-dimensions-or-getting-the-edid-the-right-way/

https://www.winvistatips.com/threads/how-to-read-monitors-edid-information.181727/

Reading Monitor Physical Dimensions, or: Getting the EDID, the Right Way

Posted on November 13, 2011by Ofek Shilon


Edit: an improvement is published in a separate post


We recently needed to know the physical size of monitors on customer machines. Getting it right was a surprisingly tedious research – and definitely something that deserves more web presence – and so the results are below.

1. GetDeviceCaps

– is the immediate answer. The argument flags HORZSIZE / VERTSIZE are advertised to give the –

Width/Height, in millimeters, of the physical screen.

Alas, as many have discovered, GetDeviceCaps just does not work as advertised with these flags.

2. GetMonitorDisplayAreaSize

– is the next obvious guess. The documentation doesn’t state whether the obtained values are in pixels or physical units – I suspect it’s vendor specific, but didn’t get to check it myself since I kept getting the dreadful LastError 0xc0262582: “An error occurred while transmitting data to the device on the I2C bus.”. Gotta say I didn’t insist too much since the entire Monitor Configuration API set is both new to Vista and already ‘legacy graphics’, which are explicitly described as–

Technologies that are obsolete and should not be used in new applications.

3. WMI

There’s a good chance that this Managed Instrumentation code  gets the job done. I didn’t get to test it, since

(1) It is exceptionally complicated (CoSetProxyBlanket anyone? How about some nice IWbemClassObjects to go with that?),

(2) WMI supports monitor classes only since Vista, which makes it irrelevant to most of the world (40%-50% as of Sep 2011).

4. Spelunking the Registry

Unlike what many, many, say, the physical display information is in fact available to the OS, via Extended Display Identification Data (EDID). A copy of the EDID block is kept in the registry, and bytes 21/22 of it contain the width/height of the monitor, in cm. Some have tried digging into the registry directly, searching for the EDID block, but the code in the link didn’t work for me and worked (I guess) for the poster by pure accident: the exact registry path to the EDID is not only undocumented, but does in practice vary from one vendor to another.

This is, however, a step in the right direction – which turned out to be:

5. SetupAPI !

Finally, here’s some code that works almost perfectly, courtesy of Calvin Guan. Turns out there is a documented way of obtaining the correct registry for a device:

  1. Call SetupDiGetClassDevsEx to get an HDEVINFO handle.
  2. Use this HDEVINFO in a call to SetupDiEnumDeviceInfo to populate an SP_DEVINFO_DATA struct.
  3. Use both HDEVICE and HDEVINFO in a call to SetupDiOpenDevRegKey, to finally get an HKEY to the desired registry key – the one that holds the EDID block.

Below is a (larger than usual) code snippet. Beyond some general cleanup, a few fixes were applied to Calvin’s original code:

(1) the REGSAM argument in SetupDiOpenDevRegKey is set to KEY_READ and not KEY_ALL_ACCESS to allow non-admins to run it, (2) Fix a small memory leak due to a missing SetupDiDestroyDeviceInfoList call (thanks @Anonymous!), (3) the monitor size is extracted from the EDID with millimeter precision, and not cm (thanks other @Anonymous!)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

#include <atlstr.h>

#include <SetupApi.h>

#pragma comment(lib, "setupapi.lib")

#define NAME_SIZE 128

const GUID GUID_CLASS_MONITOR = {0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18};

// Assumes hDevRegKey is valid

bool GetMonitorSizeFromEDID(const HKEY hDevRegKey, short& WidthMm, short& HeightMm)

{

    DWORD dwType, AcutalValueNameLength = NAME_SIZE;

    TCHAR valueName[NAME_SIZE];

    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

        if (retValue != ERROR_SUCCESS || 0 != _tcscmp(valueName,_T("EDID")))

            continue;

        WidthMm  = ((EDIDdata[68] & 0xF0) << 4) + EDIDdata[66];

        HeightMm = ((EDIDdata[68] & 0x0F) << 8) + EDIDdata[67];       return true; // valid EDID found    }   return false; // EDID not found } bool GetSizeForDevID(const CString& 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;           bRes = GetMonitorSizeFromEDID(hDevRegKey, WidthMm, HeightMm);           RegCloseKey(hDevRegKey);        }   }   SetupDiDestroyDeviceInfoList(devInfo);  return bRes; } int _tmain(int argc, _TCHAR* argv[]) {   short WidthMm, HeightMm;    DISPLAY_DEVICE dd;  dd.cb = sizeof(dd);     DWORD dev = 0; // device index  int id = 1; // monitor number, as used by Display Properties > Settings

    CString 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;

        while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0) && !bFoundDevice)

        {

            if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE &&

                !(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))

            {

                DeviceID.Format (L"%s", ddMon.DeviceID);

                DeviceID = DeviceID.Mid (8, DeviceID.Find (L"\\", 9) - 8);

                bFoundDevice = GetSizeForDevID(DeviceID, WidthMm, HeightMm);

            }

            devMon++;

            ZeroMemory(&ddMon, sizeof(ddMon));

            ddMon.cb = sizeof(ddMon);

        }

        ZeroMemory(&dd, sizeof(dd));

        dd.cb = sizeof(dd);

        dev++;

    }

    return 0;

}

SetupAPI is still not the most pleasant of API sets around, but as MSFT’s Doron Holan replied to a user preferring to dig in the registry himself:

Programming is hard. Plain and simple. Some problems are simple, some are hard. Some APIs you like, some you don’t. Going behind the back of those APIs and getting at the data yourself will only cause problems for you and your customers.

I actually had to query the dimensions of a specific monitor (specified HMONITOR). This was an even nastier problem, and frankly I’m just not confident yet that I got it right. If I ever get to a code worth sharing – I’ll certainly share it here.

EDID的获取和解析相关推荐

  1. android从服务端获取json解析显示在客户端上面,Android服务端获取json解析显示在客户端上面.doc...

    Android服务端获取json解析显示在客户端上面 Android从服务端获取json解析显示在客户端上面 首先说一下Json数据的最基本的特点,Json数据是一系列的键值对的集合,和XML数据来比 ...

  2. (仿头条APP项目)4.父类BaseFragment创建,用retrofit和gson获取并解析服务器端数据

    文章目录 父类BaseFragment创建,用retrofit和gson获取并解析服务器端数据 效果展示 创建父类BaseFragment解决代码重复问题 用retrofit和gson获取并解析服务器 ...

  3. Android 开源1:获取并解析网页信息(Jsoup)

    Android 开源1:获取并解析网页信息(Jsoup) Android 开源1获取并解析网页信息Jsoup 一程序功能 二程序界面 三程序知识点与创新点 四 总结 一.程序功能 本款APP主要是通过 ...

  4. 调用API接口 获取和解析 京东按关键字搜索商品数据

    这篇文章主要介绍了如何调用API接口 获取和解析京东按关键字搜索商品数据,帮助大家更好的理解和使用API接口. 点击测试 请求示例 <?php// 请求示例 url 默认请求参数已经URL编码处 ...

  5. python--爬虫--获取和解析存储网页内容--以薄荷网为例

    如需转载请注明出处:python–爬虫–获取和解析存储网页内容–以薄荷网为例 我们在之前的文章中已经学习了如何进行数据抓包和截取 以及分析 访问网页. 例如: 抓取app数据教程–fiddler抓包数 ...

  6. 荒岛求生html5母狼攻,荒岛求生各资源作用及获取方法解析 荒岛求生资源怎么获得...

    荒岛求生地图中有很多资源可以获取,它们各有什么作用呢?下面为大家带来荒岛求生各资源作用及获取方法解析,还不清楚的玩家一起来看看吧. 荒岛求生各资源作用及获取方法解析 1.木材:作用最大的资源,没有木材 ...

  7. 分子数据的获取、解析与结构绘制(RDKit)

    在化学信息学中,分子数据的获取与解析是最基础的部分.对于已知的化合物,我们可以从各种数据库中获取:对于未知的化合物,我们也可以构造该分子.在RDKit中,无论是从数据库中获取的分子文件还是自己构建的分 ...

  8. 【转载】EDID的简介和解析

    原文:https://www.cnblogs.com/beyond-rxl/p/9266997.html 去年对EDID做了一个解析,下面是学习EDID过程中整理的资料. 一.EDID简介 EDID: ...

  9. Apollo客户端配置获取深度解析

    Apollo客户端配置获取深度解析 Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理 ...

最新文章

  1. Spring Initializr 构建Spring Boot/Cloud工程
  2. c语言名字程序,c语言获得程序位数和操作系统位数和名称
  3. UML--9种图及关系
  4. python合并ts视频_python爬取视频网站m3u8视频,下载.ts后缀文件,合并成整视频
  5. 一张图,看懂阿里云12年的“飞天日记”
  6. Linux 设备管理和进程管理
  7. 绝地求生信号枪只能在服务器吗,绝地求生信号枪怎么用?信号枪刷新点及用法详解...
  8. tensorflow 学习资料汇总
  9. 图解PostgreSQL进程结构和内存结构
  10. OpenStack Glance(镜像服务)基础架构:Basic architecture
  11. java 实例化xpath_Java XPath示例教程
  12. winform开发框架介绍
  13. 犀牛建计算机键盘,犀牛建模基础教程 键盘建模
  14. NTFS, FAT32和exFAT文件系统有什么区别
  15. Visual Basic快速入门
  16. 网络安全——D模块答题模式
  17. Android Studio数据库增删改查。
  18. 中国石油大学《马克思主义基本原理》第二阶段在线作业
  19. Processing 案例 | 三角函数之美
  20. 获取json格式中属性—sql

热门文章

  1. 移动端ios使用fixed定位,偶现元素不显示问题(百度浏览器)
  2. 三菱PLC梯形图触点比较指令(><=)为什么加D
  3. 移动小王子--Intel Xscale处理器
  4. java与mysql笔试题_JAVA和数据库笔试题
  5. 电脑中复制提示剪切板被占用(重启资源管理器无用)
  6. kafka日志保留时间设置无效问题
  7. 完全卸载ArcGIS9.3
  8. 研报精选230411
  9. vscode调试C/C++的.vscode配置
  10. 在项目中使用 vuepress 搭建组件文档 报错 Uncaught ReferenceError: global is not defined