I have a problem where an application (written in Delphi) is behaving properly at default 96 DPI settings on all systems, but is behaving inconsistently at the "150% text size" (internally 144 dpi) setting, on different systems. It seems that on some systems, that certain text/font parts of my application are being stretched and on other systems, they aren't. I would have thought that my application, on a certain version of Windows (Win7), at a certain DPI, should behave the same way.
Either my application will make it known to Windows that it doesn't need the DPI Virtualization feature, or it will not. That much I understand. What I don't understand is how DPI changes can cause different appearance on two machines, both running Windows 7, both at 144 dpi, displaying the same fonts and forms at the same fixed sizes.
Is there some configuration-dependant elements involved in DPI Virtualization that I need to inspect in windows (registry etc)? Otherwise, how do you troubleshoot and know whether DPI virtualization is being done on your client window?
In Delphi, one has to set the TForm.Scaled property to false, if one doesn't want scaling. But what I don't understand is that when the main form's Scaled property is true, I cannot always predict the outcome.
What is most perplexing to me in my application, is that I have a control that only misbehaves in my large real application, but which does not misbehave in a standalone app where I am trying to debug just the control. To understand the control behaviour in a standalone app I was forced to make a demo app where I force the DPI awareness in via the manifest file. Then I can reproduce the control drawing glitch, although in a different form.
Here is the manifest file I use in my demo app, which exposes the problems that my controls have with dealing with high-dpi settings in windows. However, one strange thing I have found is that it is possible for an application
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<assemblyIdentity version="14.0.3615.26342" processorArchitecture="*"
name="TestProject" type="win32"></assemblyIdentity>
<description>High DPI Controls Test App</description>
</assembly>
here's an example of one of about 30 places where the controls in my application are messed up when I disable DPI virtualization in my app. This particular glitch was solved by turning off the Scaled property in my form. But in other places, having TForm.Scaled=false causes the problem, whereas in some forms, it fixes it:
Update: It turns out that some of my controls use GDI+ and that font behaviour in GDI+ contexts is different than font behaviour in normal GDI contexts, at least for certain third-party controls that use GDI+. That's a major source of headaches. Secondly, there is the spotty test coverage and poorly-defined requirements, for DPI awareness, in the VCL. Some VCL controls are based on MS Common Controls, and while it's fair to say that the underlying common controls probably work fine in high-DPI situations, not all the VCL control wrappers can be guaranteed to work correctly. So, reviewing an application for high-DPI-awareness in all its controls, as well as correct behaviour in all available windows 7 themes:
- aero glass on, at 96dpi (Default Win7 appearance on most modern hardware)
- basic theme (aero glass off) but xp themes enabled
- classic win2000 look where glass is off, as well as xp level themes,
- high contrast white
- high contrast black
- Various Other-than-96-DPI settings
..and the list goes on., and you have a pretty heavy burden, as an application developer. Whether you are a delphi user and use the VCL, or you are an MFC/ATL C++ developer, it seems to me, that supporting all of the various quirky windows modes is a burden almost too heavy to bear. So most people don't bother. Am I right?
It turns out that the quirks in my Application when the system DPI changed away from the default 96 dpi value, are in three general camps:
Some of the application's controls use GDI and some controls use GDI+. There are some differences in how a GDI and GDI+ font renders at different DPI, at least in the controls I am using.
I use a framework called VCL in delphi. In this Delphi VCL framework, some forms have TForm.Scaled=true, and some have TForm.Scaled=false. Because it requires you to think about each control in a scaled form, it is very common to have things happen that you as a UI designer will find "ugly" or unacceptable in a Scaled form. Turning Scaled off, you are left with forms that are either stretched by Windows 7 itself, in high DPI settings (DPI Virtualization mode) or which appear small and therefore, ignore the user's "request" if you like, for a 144 dpi version of your 96 dpi UI. Other people might be using other framworks in other languages, or might even be using something really old fashioned, like the Dialog Box Editor for Visual C++, where you design dialogs in "Dialog Units", which is another way of trying to separate general dialog layout, from a 1:1 correspondence to pixels. Scaling, stretching, and layout controls are a general part of UI design that must be solved in a way that matches platform requirements. In my case, the VCL does a great job of letting me design a 96 DPI glass-enabled aero app, and works great at other DPI ratings, but most of my custom controls don't. So it's another reason to stick with the controls that come with the VCL: If you care about high DPI support, your job gets harder when you try to make high DPI support work.
DPI Virtualization in turn, is controlled by a manifest setting that you must expressly include in your application. Since my application already had a custom manifest (not the one that is included with your Delphi app when you click the Enable-windows-themes checkbox in the project settings), I was able to turn this DPI virtualization on and off again, and test my application in both cases. I found that my application was not ready to run without DPI Virtualization, and thus I left Windows to its default behaviour. Other people's applications might easily work with DPI Virtualization disabled, if they use 100% vcl controls, with forms that either use Form scaling, or some other technique, to appropriately size themselves (such as the VCL ExpressLayout control from DevExpress) at a variety of font sizes, and DPI pitches.). It seems to me, that in the end, the VCL is functional enough, but that for really industrial-strength solutions, a more advanced framework than the VCL is required, to comprehensively deal with issues like "high DPI environments" properly, and that third party controls are generally not designed to work even as well as the current VCL works, in these cases. Such framework concerns are very much in evidence in the WPF framework (Microsoft) and in Java (wing), but are not part of the classic "Win16/Win32 common control framework" of the VCL.
All in all, these changes are not that different (complex) now, than in the old days, when Windows XP and other versions of Windows offered you a choice of "font sizes", whereas now, the Windows 7 UI experience tries to bury the font point size options pretty deeply, and instead offers you a "text size" changing user interface that modifies the system DPI below the surface. Both of these ways of changing your user experience result in almost every user having problems with at least one major commercial application that doesn't look, or work correctly with the resulting changes. As ultra-high dot-pitch displays become more common in the consumer PC landscape, this problem will probably get worse and worse, and UI design around more suitable frameworks will be required.