【问题标题】:Screen Pixel Resolution in mm以毫米为单位的屏幕像素分辨率
【发布时间】:2011-01-01 06:23:20
【问题描述】:

是否可以使用 Win32 API 获得以毫米为单位的屏幕像素分辨率?我有一个应用程序,它在我的 1280x1024 显示器上显示 0.3472222222222222 作为此值,分辨率为 96 dpi 。但我不知道它是如何得到这个值的。任何线索都会有所帮助。如果需要,我也可以使用 MFC。

编辑 抱歉,我说的软件没有使用当前的屏幕分辨率。它正在从某个配置文件中读取它。

【问题讨论】:

  • 25 / 72 = 0.347222。不知道你从哪里得到 25 个。

标签: c++ c mfc winapi


【解决方案1】:

使用GetDC 函数获取监视器的句柄,然后调用GetDeviceCaps 函数获取监视器的尺寸(以毫米为单位)。例如:

HDC monitor = GetDC( NULL );
int horizSize = GetDeviceCaps( monitor, HORZSIZE );
int vertSize = GetDeviceCaps( monitor, VERTSIZE );

【讨论】:

    【解决方案2】:

    每像素 0.3472222222222222 毫米实际上相当于大约 73 dpi。 Windows 使用两种标准设置 72dpi 和 96dpi,但也支持自定义值。这些是标称值,可能与物理屏幕没有任何关系。例如,可以将物理上 96dpi 的屏幕设置为 72dpi,这将影响各种应用程序中图像和布局的缩放以及系统字体和图标的大小。

    Windows 的默认值为 72dpi,我发现某些应用程序(通常在其“关于”和对话框中)在设置为其他值时无法正确呈现。如果您的应用程序报告 0.34,它似乎设置为 72dpi 或自定义值,而不管物理分辨率如何。当设置为匹配物理分辨率时,例如 Word 中的页面宽度设置为 100% 的缩放级别时将匹配物理纸张大小。由于此指标可由最终用户设置,因此与实际分辨率没有直接关系。

    【讨论】:

      【解决方案3】:

      Get device caps for the monitor 为您提供以像素和毫米为单位的尺寸:

      HDC screen = GetDC(NULL);
      int hSize=GetDeviceCaps(screen,HORZSIZE);
      int hRes=GetDeviceCaps(screen,HORZRES);
      float PixelsPerMM=(float)hRes/hSize;   // pixels per millimeter
      float PixelsPerInch=PixelsPerMM*25.4; //dpi
      

      【讨论】:

      • 但这些是合乎逻辑的英寸不是吗?
      • 每英寸有 25.4 毫米——不是 2.54。
      • Ponting 在他上面的评论中是正确的,这给出了逻辑英寸,这不是通常意义上的单位。
      【解决方案4】:

      MSDN 中关于编写“DPI 感知”应用程序的部分非常值得任何有兴趣为可变显示分辨率提供体面支持的人阅读。用于获取相关设备和系统指标的 API 描述为here

      【讨论】:

        【解决方案5】:

        下面的代码 sn-p 证明提供了最好的结果。

        ID2D1Factory* m_pDirect2dFactory;
        D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory);
        FLOAT dpiX, dpiY;
        m_pDirect2dFactory->GetDesktopDpi( &dpiX, &dpiY );
        

        【讨论】:

          【解决方案6】:

          我在 Windows 7 上也遇到过类似的问题,并尝试了不同的方法,但直到我找到了正确的答案:http://ofekshilon.com/2011/11/13/reading-monitor-physical-dimensions-or-getting-the-edid-the-right-way/

          它适用于不同的屏幕尺寸!

          #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;
          }
          

          【讨论】:

          • 这是真正无效的代码。在多屏幕系统上运行它。线索:TargetDevID 从未在 GetSizeForDevID() 方法中使用。
          • 不能说真的无效,因为:1. 是可编译的,2. 它适用于讨论的用例(单屏显示器)。事实上,它远非一个好的/完美的代码,它并不意味着与多屏幕一起工作。但是,只要花一点时间,您可能会发现这对您的多屏解决方案研究很有用。
          • 那为什么要进行while循环呢?一个 while 循环表示“给我每台显示器”,如果它是用于一个显示器的,那将是对 EnumDisplayDevices() 的一次调用。就像我说的,这段代码是无效的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多