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. Note we only cover traditional Windows desktop applications, not Windows Store (“Metro, Modern, Universal”) applications. The latter use a different API which provides its own scaling mechanism.
- Scaling Methods describes the available scaling methods
- Changing DPI Settings explains how to change scaling methods
- Application Types examines how applications scale (or don’t)
Traditionally, native Windows desktop applications rely on two mechanisms to draw on the screen:
- Call functions in the Graphics Device Interface (GDI) API to address the display. Usually, GDI coordinates map directly to screen pixels, regardless of monitor size and pixel density.
- Use Windows system fonts to draw text. This is optional, but most desktop applications use system fonts for most of their graphical user interface (GUI).
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 minimum 96 DPI, and both methods attempt to scale up the size of display elements accordingly.
Windows XP Style DPI Scaling
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 DPI Virtualization
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 modern mobile phones (300+ DPI). Unfortunately they don’t, and application windows scaled up in this fashion look annoyingly blurry at the common pixel density of 120 DPI. Prior to Windows 8.1 Microsoft therefore disabled DPI virtualization by default, unless you choose a pixel density greater than 120 DPI. (Starting with Windows 8.1 Microsoft apparently assumes everyone has high-density displays.)
For more information about both scaling methods from a developer perspective, see the MSDN article Writing DPI-Aware Desktop and Win32 Applications, currently covering Windows XP–8.1. This thorough article also contains a sample manifest for DPI awareness, as well as sample screenshots for the various scaling methods and tips on display scaling in native code. Also see Chuck Walbourn’s Manifest Madness for additional information on Windows 7–10.
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. Lastly, see DPI Scaling in Windows GUIs for an evaluation of .NET and Java GUI frameworks with regard to DPI scaling.
Changing DPI Settings
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 Changes
Windows 8.1 entirely removes the check box for XP style scaling and always enforces the default behavior if per-monitor scaling is disabled. That is, 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, and it enforces DPI virtualization at all scaling levels including 120 DPI. 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.
Windows 10 Changes
From a technical perspective, Windows 10 adds just one small feature: you can now explicitly specify the DPI scaling for each monitor (assuming per-monitor scaling is enabled), whereas Windows 8.1 would automatically pick a scaling for each monitor based on your overall size preference.
However, Windows 10 massively changes the user interface for DPI scaling. Per-monitor scaling is now exclusively controlled through the “modern” Settings app. System-wide scaling is still available but hidden inside a reworked Control Panel page and not documented as such. These changes are too extensive to cover in this article, so I direct you to my dedicated blog post.
Help, my text is blurry after upgrading!
Windows 8.1 defaults to a per-monitor scaling mechanism that has the annoying side effect of enforcing DPI virtualization at all scaling levels, even the previously exempted 125% (120 DPI). So if you’re running at that scaling level and you’re upgrading to Windows 8.1, you may experience blurry text in applications that formerly looked crisp. There are two possible solutions: either disable per-monitor scaling globally, as described above, or manually disable DPI virtualization for each blurry-looking application.
Windows 10 makes DPI virtualization permanent at all scaling levels, even when per-monitor scaling is disabled. Users running at 120 DPI must therefore manually disable DPI virtualization for each individual application afflicted with blurry text. (Thanks to LB for pointing this out!)
Help, my system fonts are the wrong size!
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–10, 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 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 Java Swing applications without scaling options. 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.
Choosing a Scaling Method
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.
- If you are so incredibly lucky as to use only applications that are both DPI-aware and set the required flag, it doesn’t matter which scaling method you choose. All applications will use XP style scaling, and DPI virtualization will never get used.
- If you use only well-written applications that are DPI-aware, but some of them don’t set the required flag, you should disable DPI virtualization. That way all applications will display correctly, without any blurry bitmap scaling. If your monitor has a really high pixel density so that scaled bitmaps no longer look blurry, you might want to enable DPI virtualization anyway.
- If you do have one or more poorly-written application without any DPI awareness, you must enable DPI virtualization unless you’re willing to tolerate the application’s screwed-up GUI. Unfortunately, this results in a secondary problem because Microsoft designed this option the wrong way around. DPI virtualization is opt-out rather than opt-in: you can only enable it for the entire system, then you must selectively disable it for individual applications.
As a reminder, starting with Windows 8.1 you no longer have 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, or use Windows 10 or later, or use per-monitor scaling on Windows 8.1, every program that isn’t DPI-aware will use DPI virtualization.
Opting Out of DPI Virtualization
Once you have decided to enable DPI virtualization, or you’re running Windows 8.1+ 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 since 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.