Andy Li
Andy Li

Reputation: 6034

Getting actual screen dpi/ppi under windows

I would like to get the actual screen dpi/ppi, not the dpi setting used for font in C++.

I tried with the following codes:

Version 1, reports 72 dpi, which is wrong.

SetProcessDPIAware(); //true
HDC screen = GetDC(NULL);
double hSize = GetDeviceCaps(screen, HORZSIZE);
double vSize = GetDeviceCaps(screen, VERTSIZE);
double hRes = GetDeviceCaps(screen, HORZRES);
double vRes = GetDeviceCaps(screen, VERTRES);
double hPixelsPerInch = hRes / hSize * 25.4;
double vPixelsPerInch = vRes / vSize * 25.4;
ReleaseDC(NULL, screen);
return (hPixelsPerInch + vPixelsPerInch) * 0.5;

Version 2, reports 96 dpi, which is the Windows dpi setting for font, but not the actual screen dpi.

SetProcessDPIAware(); //true
HDC screen = GetDC(NULL);
double hPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSX);
double vPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSY);
ReleaseDC(NULL, screen);
return (hPixelsPerInch + vPixelsPerInch) * 0.5;

Upvotes: 26

Views: 46368

Answers (4)

Adrian McCarthy
Adrian McCarthy

Reputation: 47954

What you're asking for is, unfortunately, not possible in the general case.

Windows doesn't know the physical screen size. Windows might know that your screen has 1024x768 pixels, but it doesn't know how big the screen actually is. You might pull the cable out of your old 13" screen and connect it to a 19" monitor without changing the resolution. The DPI would be different, but Windows won't notice that you changed monitors.

You can get the true physical dimensions and DPI for a printer (assuming the driver isn't lying), but not for a screen. At least not reliably.

UPDATED

As others have pointed out, there are standards for two-way communication between newer monitors and the OS (EDID), that might make this information available for some devices. But I haven't yet found a monitor that provides this information.

Even if EDID were universally available, it's still not solvable in the general case, as the display could be a video projector, where the DPI would depend on the zoom, the focus, the lens type, and the throw distance. A projector is extremely unlikely to know the throw distance, so there's no way for it to report the actual DPI.

Upvotes: 15

Katastic Voyage
Katastic Voyage

Reputation: 1044

I'm honestly confused by the answers here.

Microsoft has a GetDpiForMonitor method:

https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx

And monitors DO expose their physical dimensions to tools. You can read your monitors width and height, in centimeters, using the HWiNFO64 tool. So if they're getting it (DDI?), it stands to reason that you can access that information yourself.

Even a different Stack Overflow post mentions using WmiMonitorBasicDisplayParams to get the data.

How to get monitor size

So the top post is flat-out, 100%, wrong.

Upvotes: 16

James Bedford
James Bedford

Reputation: 28962

I think what you're after is:

GetDeviceCaps(hdcScreen, LOGPIXELSX); GetDeviceCaps(hdcScreen, LOGPIXELSY);

Upvotes: 0

MGR
MGR

Reputation: 323

Getting DPI information is found to produce exact value using the below method.

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

Upvotes: 1

Related Questions