msdnmagazine.com February 2014 13
pixel density of the screen, but in reality many factors infl uence
the DPI value—such as form factor and distance to the screen—
so the eff ective DPI value you end up using has little to do with an
actual inch. Th ese four options also represent the full spectrum of
possibilities, but what a particular PC might off er depends on the
vertical resolution of its displays.
Th is is illustrated in Figure 5. Th ese limits are intended to keep
UI elements from getting cropped off the bottom of the display. If
your display has fewer than 900 lines of vertical resolution, then
you won’t have any options and the 100 percent scaling factor will
be all there is. As the vertical resolution of your display increases,
you’re presented with more options until you reach 1,440 lines of
vertical resolution, at which point you experi-
ence all four possible options. These options
do not, however, affect the scaling on all
monitors equally. Th is is where the concept of
per-monitor DPI scaling comes from. It isn’t
entirely obvious at fi rst glance because the OS
takes into account both the vertical resolution
as well as the native DPI for the physical display.
As a developer of desktop applications, it’s
important to realize there are now two scaling
factors that may be at play. Th ere’s the system
DPI scaling factor and then there’s a per-monitor
DPI scaling factor. Th e system DPI scaling factor
corresponds to one of the values in Figure 4—
with the exception of devices such as Windows
Phone—and remains constant for the duration
of the logon session. Th e system DPI value is
based on the initial radio button shown in Fig-
ure 2 or the slider position shown in Figure 3.
To retrieve the system DPI value, you start by
getting hold of the desktop device context. Yes,
this boils down to the old GDI API, but it has noth-
ing to do with GDI rendering and is only a historical footnote. First,
to get a handle representing the desktop device context, you call the
GetDC function with a nullptr instead of a window handle. Th is
special value indicates you want the device context for the desk-
top as a whole rather than a particular window:
auto dc = GetDC(nullptr);
Naturally, you must remember to free this
handle when you’re done:
ReleaseDC(nullptr, dc);
Th e fi rst parameter is the handle to the win-
dow to which the device context refers. Again,
a nullptr value represents the desktop. Now,
given the device context, you can use the Get-
DeviceCaps function to retrieve the system DPI
scaling factor for the x and y axes as follows:
auto x = GetDeviceCaps(dc, LOGPIXELSX);
auto y = GetDeviceCaps(dc, LOGPIXELSY);
Having a diff erent value for the x and y axes
dates back to the dark ages when printers rou-
tinely off ered diff erent scaling factors horizontally
and vertically. I’ve never come across a display
that off ers up non-square pixels, but I hear they
do exist in some industries for which special
graphics cards have been developed. LOG-
PIXELSX and LOGPIXELSY represent the
number of pixels per logical inch along the
Figure 3 Windows 8.1 PC Setting Affecting Dynamic
and Per-Monitor Scaling for the Desktop
Figure 2 Pre-Windows 8.1 PC Setting Affecting Desktop Applications
It’s important to realize there
are now two scaling factors that
may be at play.