Setting High DPI displays awareness with windows application Manifest in RAD Studio
In the previous article we quickly went through the evolution of HiDPI support in Windows and got to a question: what if an application developer did not implement support for HiDPI, or it even wasn’t a thing, when the app was written? How will Windows know that, and how will it behave? Or: How will Windows behave if an app does not support dynamic scale changes? How will it distinguish between apps with different levels of support for HiDPI? The answer to these questions is Application Manifest – special metadata added during compilation of Windows executables. Settings in the manifest have been evolving along with each new Windows version. DPI Awareness settings in manifest of Windows executable file, in the latest releases of Windows 10, can have six different values, options screen for VCL project in RAD Studio 11 Alexandria:
Manifest page in project options
Let’s have a look at how each of the values works:
None – A section related to HiDPI support will not be included in the manifest. Apps that have no manifest at all share the same behavior. On the screenshots from Windows 7 above you can see a checkbox “Use Windows XP style DPI scaling” (also available in Windows Vista, 8 and 8.1). If the checkbox is not set, an app will behave as Unaware, otherwise it will behave as System Aware.
Unaware – An application does not support HiDPI. If HiDPI is actually enabled, this will trigger so-called “DPI Virtualization” mode. In this mode Windows will “lie” to the app, that HiDPI is not enabled (100% scaling, DPI=96). It will also calculate values of screen sizes, taskbar height and other UI elements for 100% scaling and pass to the app, when it asks. When an app finishes drawing its UI (processing WM_PAINT message), Windows will take that image, and scale it using regular image scaling techniques. For 125% <= scaling <= 175% this will result in blurred image:
For 200% scaling Windows will use so called “integer scaling” – every pixel will be replaced with four pixels of the same color. This will result in pixelated but crisp image:
GDI Scaling – It is almost the same as Unaware, but with a little bit of magic from Windows developers. During processing of WM_PAINT message, Windows will skip most of the draw calls. For example, it will skip text calls, and calls to Theme API. But it will remember where everything should have been drawn. Then it will scale the image of the UI using image scaling techniques, and only after that it will draw, on top of it, all elements that have been skipped, but using correct scaling value. Of course, this mode has its limitations. For example, it does not work with double buffered controls in VCL:
Users can force usage of this mode for any third-party app through Windows compatibility settings. It is called “System (Enhanced)”:
System Awareness – An app supports HiDPI, but all calculations are done only once, during the app startup. System DPI is determined during the user session startup in Windows 10, or during the system startup in Windows 8 and below. If there are multiple screens with different scaling values, Windows will use scaling of the main screen. If scaling changes when the app is already running, DPI virtualization will be used. Such changes can happen when a user is dragging an app window to a screen with different scale, or is connecting to a running user session through RDP from a computer with different scaling. Below there is example of System Aware and Unaware apps started on a screen with 200% scale (System scale) and later moved to a screen with 100% scale:
DPI virtualization is active only for an Unaware app
DPI virtualization is active only for a System Aware app
Per Monitor v2 – This mode allows apps to receive notifications about scale changes at any time, not just during the startup. Also, apps should be ready for a situation when one of its windows will be on a screen with 100% scale, and another – on a screen with 200% scale. This makes development of such apps a pretty complicated task, for example you have to use TVirtualImageList instead of old TImageList. However, this mode is recommended for any new projects, and is default in RAD Studio.
Per Monitor – This mode is sort of deprecated. It allows apps to receive notifications about scale changes, just like Per Monitor v2, but elements drawn by Windows are not scaled. For example, the same experiment with moving app windows from a screen with 200% scaling to a screen with 100% scaling:
Note that checkbox and radio buttons are drawn with artifacts, and scroll thickness in memo is not scaled.
All these modes can be important for VCL apps, but what about FMX? Well, FMX has good support for HiDPI scaling all the time, thanks to mobile platforms. There were a few issues on desktop platforms, but they have been fixed in RAD Studio 11 Alexandria. So, for FMX projects switch to Per Monitor v2 and stick with it.
If you want to know more about HiDPI support in Windows,there articles written by the Microsoft team will be interesting for you: