.NET

Coding for High-DPI Displays in Windows

Deliver crisp text and images on all Windows monitors, regardless of settings.

In the first article in this two-part series on coding for high-DPI displays on the Windows desktop, I explained high-DPI configurations in Windows 8.1 and their effect on the three different kinds of applications: DPI-unaware, system-DPI aware, and per-monitor DPI aware. In this article, I provide a complete example of a system DPI-aware Win32 application and then I'll convert it to a per-monitor DPI-aware application that always provides crisp text and images to Windows 8.1 users.

Checking the DPI Awareness of Each Process

The latest versions of Process Explorer allow you to easily check the DPI awareness of each process. The default view doesn't include the DPI Awareness column. You just need to right-click on the column headers, select Select Columns…, check the DPI Awareness checkbox, and click OK. This way, Process Explorer will add the DPI Awareness column and will display the following three possible values for each running process:

Unaware

System Aware

Per-Monitor Aware

I'll use Process Explorer to make sure that the changes in the DPI Awareness configuration for each new build are reflected in the process.

Creating a System DPI Aware Win32 Application in Visual Studio 2013

You can use the following two mechanisms to set the DPI-awareness level for a process:

Declaratively: Specify the desired level of awareness in the dpiAware entry of the application manifest. This way, DWM sets the specified DPI awareness level when the user launches the application. Visual Studio 2013 enables you to set the DPI-awareness level without having to edit the manifest tool.

Procedurally: Call the SetProcessDpiAwareness function with the appropriate value from the PROCESS_DPI_AWARENESS enumeration. The function must be called before any Win32 API call that makes DWM begin virtualization.

It is a good practice to use the application manifest instead of calling the SetProcessDpiAwareness function. However, there are specific cases in which you might find it more convenient to make the API call. For the system DPI-aware sample application, I use the recommended process for declaring the DPI awareness level of a sample application and I take advantage of the features included in Visual Studio 2013 to do so. However, it will be necessary to merge a manifest file for compatibility reasons when converting the application to per-monitor DPI aware.

Create a Visual C++ Win32 Project in Visual Studio 2013. I'll use DPIAware for the solution name. Make sure "Windows application" is selected in Application type in the Win32 Application Wizard. This way, you will have the basic structure for a C++ Win32 Windows application, and I can focus on the necessary changes in the code for the example. By default, Visual Studio 2013 creates a simple Win32 application with some menu items and an About dialog box. These elements are going to be useful to test how the app works with different DPI aware settings, even before I make any changes to the code.

To follow along, make sure your display settings in the Display Control Panel item use a scaling level higher than 100% (96 DPI) you need at least 125% (120 DPI). If your settings specify a scaling level equal to 100% (96 DPI), you won't notice the changes I'll describe later. However, don't forget that any changes in the scaling level configuration will have an impact on all your applications.

By default, the generated Win32 application is DPI-unaware. Execute the application and you will notice the text in the menu bar is blurry because the DWM has virtualized the application window and is scaling it. Select Help | About… and you will also notice the text displayed within the About dialog box and the text for the OK button is blurry. If you use Process Explorer to check the DPI Awareness value for the generated executable (DPIAware.exe), you will see the Unaware value.

Now, stop the execution and right-click on the project name (DPIAware) within Solution Explorer and select Properties. Visual Studio will show the Property Pages dialog box for the project. Then, select Configuration Properties | Manifest Tool | Input and Output | DPI Awareness, select High DPI Aware from the dropdown menu and click OK. You can achieve the same effect by merging in a manifest file with the following XML to the application manifest. Notice that the true value for dpiAware indicates that the application is system DPI-aware.

As I explained earlier, in this case, it is easier to use the setting in the dialog box. I'll explain how to merge in a manifest file shortly.

Now, execute the application and you will notice the text in the menu bar is crisp and clear. Now, the application is DPI-aware and DWM doesn't virtualize it. There is no code to scale the fonts, and therefore, the text in the About… dialog box is probably going to be too small. If you use Process Explorer to check the DPI Awareness value for the generated executable (DPIAware.exe), you will see the System Aware value.

Open the stdafx.h header file and add a line that includes the ShellScalingAPI.h header. It is necessary to make a call to the GetDpiForMonitor API function. The following lines show the resulting code for stdafx.h.

It is necessary to add shcore.lib in the linker dependencies. You just need to right-click on the project name, select Properties, and then Configuration Properties | Linker | Input | Additional Dependencies. Add shcore.lib; as a prefix to the existing additional dependencies and click OK.

The following lines show the initial code for the DPIAware.cpp source file:

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!