Windows Vista and later offer two mechanisms to accommodate monitors with a high pixel density (dots per inch, DPI): enlarged system fonts and whole-window bitmap scaling. Unfortunately, trying to make all your applications work with either setting can be aggravating, thanks to a combination of lazy developers and bad decisions made by Microsoft.
This page is intended to help users of high DPI settings understand and fix those problems. Please note that we only cover traditional Windows desktop applications, not Windows Store (“Metro”) applications. The latter use the new WinRT API which provides its own scaling mechanism.
Traditionally, native Windows desktop applications rely on two mechanisms to draw on the screen:
In the old days, most monitors had the same pixel density of about 96 DPI, so GUIs drawn this way looked roughly the same on every system. But as pixel densities increased, application GUIs shrank in terms of centimeters or inches. Small text and other fine details became increasingly harder to see.
So Microsoft thought it would be a good idea to build some kind of display scaling into Windows. Both of the following methods are triggered by selecting a custom DPI setting that is higher than the standard 96 DPI, and both methods attempt to scale up the size of display elements accordingly.
The first of these methods dates back to Windows XP and is therefore known as Windows XP style DPI scaling. This method does not actually scale an application GUI as such. Only the system fonts and other system UI elements are enlarged at higher DPI settings.
Otherwise, applications still draw their GUIs with a 1:1 correspondence of specified GDI coordinates to visible screen pixels. The only difference in their visual appearance is that any text drawn using system fonts is suddenly bigger, e.g. text labels on buttons. This causes obvious problems which we’ll get to in a minute.
Windows Vista introduced a second option, rather lamely called “display scaling” with no further qualification, so as to maximize user confusion. We’ll use the more descriptive internal name: DPI virtualization. When this option is enabled, Windows still performs XP style scaling. Just as before, the sizes of all system fonts and system UI elements are increased.
The difference is that applications which can handle high DPI settings are now expected to inform Windows of this fact. Such applications must set a new “DPI-aware” flag, either by calling the Win32 API function SetProcessDPIAware or preferably by embedding an application manifest with the flag dpiAware. If this DPI-aware flag is missing, Windows first renders the entire application window to an internal bitmap using 96 DPI sizes, and then scales up that bitmap to the current DPI setting before putting it on the screen.
This would be a fantastic scaling method if all our monitors had the pixel density of the latest iPhones (326 DPI). Unfortunately they don’t, and application windows scaled up in this fashion look annoyingly blurry at the common pixel density of 120 DPI. Microsoft therefore disables DPI virtualization by default, unless you choose a pixel density greater than 120 DPI.
For more information about both scaling methods from a developer perspective, see the MSDN article Writing High-DPI Win32 Applications. This lengthy article also contains a sample manifest to declare an application as DPI-aware, as well as sample screenshots for the various scaling methods and tips on display scaling in native code.
Unfortunately, the article currently only covers Windows XP through 7. See Writing DPI-Aware Desktop Applications in Windows 8.1 Preview (Word DOCX) and Chuck Walbourn’s Manifest Madness for additional information on Windows 8 and 8.1.
See DPI Scaling in Windows GUIs for an evaluation of popular GUI frameworks with regard to DPI scaling. You might also wish to check out Andrew McKinlay’s The Joys of High DPI for a nice (and terrifying) war story on working with high DPI in Windows 7.
On Windows 7/8, open the Control Panel, then choose “Appearance and Personalization”, then “Display”, and finally select “Set custom text size (DPI)” (Windows 7) or “Custom sizing options” (Windows 8). You will see the following dialog (Windows 7 screenshot, Windows 8 is nearly identical):
The drop-down box at the top lets you enter the desired DPI setting as a percentage value, where 100% equals 96 DPI. The 125% in the screenshot therefore equals 120 DPI. Up to Windows 7, the actual DPI value (“120 pixels per inch”) is shown next to the system font size. Windows 8 and later inexplicably drop the DPI value, so you have to calculate it yourself.
You can also put a ruler to your screen and attempt to match its markings by dragging the displayed ruler. The check box outlined in red at the bottom determines whether to only use Windows XP style DPI scaling or also Windows Vista’s new DPI virtualization. If it is unchecked, as in the screenshot, then DPI virtualization is enabled.
Rant. This dialog is a usability trainwreck. The check box seems to disable XP style scaling. But that scaling method (which only enlarges system fonts and other system UI elements) is effectively always enabled when you run at high DPI. What the check box actually controls is the exclusive use of this method, versus the additional use of DPI virtualization for applications that lack the DPI-aware flag. So the check box doesn’t control the scaling method stated in its label, but a different scaling method not mentioned anywhere – and it enables that method when it is unchecked!
Windows 8 Bug. In addition to being incomprehensible, this dialog also appears to be buggy in Windows 8. Generally everything works as in Windows 7, but the state of the check box doesn’t stick at 150% and above. When you check it and confirm, DPI virtualization is correctly disabled and stays that way. However, the check box itself will appear unchecked again the next time you open this dialog.
Windows 8.1 entirely removes the check box for XP style scaling and always enforces the default behavior, i.e. DPI virtualization is never used at 120 DPI but is always used at higher pixel densities, for those programs that don’t declare themselves DPI-aware. If some applications suddenly appear blurry, you must manually opt them out of DPI virtualization.
Windows 8.1 allows multiple monitors to use individual DPI settings. However, this feature also forces DPI virtualization on legacy applications that are dragged between monitors with different settings. To avoid this you can disable per-monitor DPI scaling globally, using the new option “Let me choose one scaling level for all my displays.”
Lastly, Windows 8.1 adds a dedicated radio button for the existing 200% setting, and a new API to let developers selectively disable DPI virtualization. See my review for more information from a user perspective, and my earlier preview coverage with some links for developers.
Sometimes, after changing DPI settings, you may notice certain system fonts that are either too big or too small for your new settings. The likely cause is that you were using a custom desktop theme based on your old DPI settings. Windows does not dare scale the fonts of custom themes.
If you actually did create a custom desktop theme and want to retain it, you’ll have to edit the fonts yourself to adapt them to your new DPI settings. However, Windows has an annoying habit of “helpfully” creating custom themes all by itself, for whatever reason. So if you never wanted a custom desktop theme to begin with, delete it and revert to a standard theme.
On Windows 7/8, open the Control Panel, choose “Appearance and Personalization” and then “Personalization”. If you see a selected entry in the “My Themes” row at the top, that means Windows is using a custom theme which is messing with your system font scaling. Select a standard theme instead, e.g. the first entry under “Aero Themes” (Windows 7) or “Windows Default Themes” (Windows 8), and delete the unwanted “My Themes” entry. All system fonts should now appear correctly.
Now let’s see how existing Windows applications deal with high DPI settings (or not). The following decision matrix summarizes the situation, then we’ll explain the various cases in more detail.
|No DPI-Aware Flag||DPI-Aware Flag|
|Not DPI-Aware||Must use DPI virtualization||Needs fix by developer|
|DPI-Aware||Must force XP style scaling||Always scaled correctly|
Applications with no DPI awareness at all — These are either very old or very poorly written, but nonetheless still disturbingly common. One notorious example is Apple’s iTunes for Windows. Here lazy developers use system fonts in their GUI, but rather than querying Windows for the actual font sizes they simply hardcode the 96 DPI sizes into their window layout, naturally screwing up the GUI when higher DPI settings increase those sizes.
Such applications require the new DPI virtualization, fuzziness be damned; otherwise you’ll encounter problems ranging from cut-off text to overlapping controls, sometimes making the GUI entirely unusable (although that is fortunately rare). Over the years I’ve collected some sample screenshots of broken applications.
Applications with DPI awareness but no DPI-aware flag — These are typical XP-era applications. Here the developers take care to obtain the actual system font sizes before constructing their GUI. Such applications display correctly under XP style scaling. Unfortunately, since they don’t set the proper flag to inform Windows of this fact, DPI virtualization will default them to fuzzy bitmap scaling. That is both unnecessary and undesirable, so you’ll want to force XP style scaling.
Applications with DPI awareness and DPI-aware flag — This is the newest type of applications, and the only one that’s entirely unproblematic regardless of your DPI settings. The DPI-aware flag is set automatically for Windows Presentation Foundation (WPF) and GDI+ applications, as these APIs provide built-in layout scaling. Developers using the old GDI API and (surprisingly) Windows Forms need to manually flag their DPI-aware applications.
Applications without DPI awareness that nevertheless set the DPI-aware flag — These are even worse than totally DPI-unaware applications. Examples include GUIs that scale decently to 120 DPI but not above, or JavaFX applications with explicit unscaled coordinates. There’s nothing you can do here, as Windows won’t force such programs to use DPI virtualization. Once the DPI-aware flag is set, the application must scale itself, however poorly. You can only nag the developers to fix their product – or use something else.
Once you have decided that you want to use a high DPI setting, your choice of scaling method depends on the applications you’re running. Keep in mind that disabling DPI virtualization means enabling “Windows XP style DPI scaling” and vice versa, using the poorly-worded check box.
As a reminder, Windows 8.1 no longer gives you a choice in this matter. If you’re running at 120 DPI (125%) every program is forced to use XP style scaling, and if you’re running at a higher pixel density every program that isn’t DPI-aware is forced to use DPI virtualization.
Once you have decided to enable DPI virtualization, or you’re running Windows 8.1 at more than 120 DPI where you have no choice, you must now scour your system for any DPI-aware applications that lack the corresponding flag, and opt them out of fuzzy bitmap scaling. This reverts them to the XP style scaling they were designed for. There are two ways to do this, one that works only for 32-bit applications and one that also works for 64-bit applications.
32-bit Applications — This is simple: right-click on the executable in Windows Explorer, select the “Properties” dialog, switch to the “Compatibility” tab, and check the option “Disable display scaling on high DPI settings”. That’s all, and in Windows 8.1 this also works for 64-bit applications.
64-bit Applications — For no apparent reason other than to annoy 64-bit users, Windows 8 and earlier disabled the above check box for 64-bit applications, even though the option itself is perfectly functional when set directly in the registry! So you’ll have to start up Registry Editor and navigate to this key:
Now add a string value (REG_SZ) whose name is the full path to the application executable and whose value is HIGHDPIAWARE. I recommend that you first modify a few 32-bit applications as described above, so you can see some example values in this registry key.
So that’s how to use high DPI settings on Windows Vista and later. And if you have ever wondered what the compatibility option “Disable display scaling on high DPI settings” is for, and why it didn’t do anything on your system, now you know: it’s only effective if you have enabled system-wide DPI virtualization, and then only for applications that are bitmap-scaled because they don’t set the DPI-aware flag.