2

I'm trying to read the physical size of my two monitor, for learning purpouses...

I'm doing this because I need to know exactly the distance that the mouse travels along the screen (in centimeters).

I have tried the option of the DPI, but scren always returns 96 DPI (if the scale is 100%, I had read the following)

But this is not real, because of this:

My first monitor has:

93 DPI

By dividing, 600 px / 6,417323 inches we get = 93,4 ... dpi

Aprox, 93,4 DPI.

And my second monitor:

84,6 DPI

84,6 DPI, 12 less units than the average monitor, I suppose.

So, we can't take this, because this is very unnacurate. And I want to be precise.


I tried by getting the real centimeters (reading this) and using PInvoke for Interop calls.

But as @Andreas Rejbrand has said, this returns a big value (1600 x 900 mm, a screen of 1,6 meters by 90 centimeters, that's not logic, my biggest screen has 52 centimeters by 29 centimeters, dividing 1600/900 returns almost the same as 52 by 30, that is 1,7777 but is this useful for me???)

PD: Asking to the user is not an option because they can lie to me, I don't was such things.


Another option was searching in the WinAPI for solutions, and I had found the following: (I think I will be downvoted for this xD, but I want to explain eveything I done)

Under the last answer I shared I found the following:

https://stackoverflow.com/a/3858175/3286975

This is edited by someone, I click the revisions and the user shared the following:

How to obtain the correct physical size of the monitor?

In a comment we can see the following link:

https://ofekshilon.com/2014/06/19/reading-specific-monitor-dimensions/

Well, we can find the following code:

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

I have been searching in PInvoke this, and examples, but I'm very lost, because I don't know if we can translate it all to C#, or is only a C++ example that can't be translated. I suppose that it can be translated, but I don't know how, I'm very newbie at interoperability calls.

PD: I have found this: http://www.programering.com/a/MDO2YjMwATc.html but I don't know yet which methods I have to use for translating the code into C# and the parameters I have to pass.

So, if any one can teach me how to figure this out, If you want to give some codes for me, that's good, but I think that good explanation is enough. i don't know.

And if there are better options to do this, please, tell me.

Because, my final solution will be applying this (centimeters of screen) to this: https://stackoverflow.com/a/422333/3286975

Also, I'm seeing that DPI are different from PPI, I'm maybe I'm searching for PPI.

Thanks in advance!

z3nth10n
  • 2,341
  • 2
  • 25
  • 49
  • You might want to take a look at [this SO question](https://stackoverflow.com/questions/577736/how-to-obtain-the-correct-physical-size-of-the-monitor). – Ron Aug 30 '17 at 14:56
  • 3
    You are wasting your time trying to make it work, the VESA industry group standard that governs the plug & play protocol is universally implemented imperfectly. Cut-throat competition in the market segment is the underlying reason. It never actually matters, perceived DPI depends on how far the user sits away from the screen. And the user modifies the setting only to keep the text in the windows comfortably readable. Simply use a tweak config setting to allow the user to get it right. – Hans Passant Aug 30 '17 at 14:57
  • There is where I get the last code I posted, but there isn't any code in C#... I don't know excactly how can I use it in WinForms. Thanks anyway @Ron – z3nth10n Aug 30 '17 at 14:58
  • Thanks @HansPassant, so there isn't a way to meause it?? Although, this is not exactly? – z3nth10n Aug 30 '17 at 15:00

0 Answers0