1
votes

This is follow-up question to Handle runtime change of DPI (text size) on Windows 10

Windows 10 allows runtime change of DPI without restart (logon/logoff) of the system. When DPI is changed, and the system detects that the application cannot handle runtime DPI change, it scales the application windows pixel-wise. What is similar to the compatibility behavior seen in previous versions of Windows. Except that in this case, the system can even scale down, not only up.

The strange thing is, that the application restart won't help. The system seems to remembers that the application did not respond correctly to the change of scaling and still behaves as before (the application believes the scaling has not changed and the system scales the windows pixel-wise). Only system logon/logoff helps resetting to the correct scaling.

Is there a way to reset the compatibility mode programmatically, to allow the user to restart the application only, not whole system? (as is a very first step towards full support for runtime DPI change)


I'm using C++ Builder, so I'm looking for a pure WinAPI solution, no WinForms.

1
Again you should read the docs on MSDN. Also, dpi change without logoff has been possible since Win 8.1. That's documented on MSDN. You might think I am being rude, but surely reading the docs is step 1.David Heffernan
If you want prevent the DPI scaling of your App, you can use the SetProcessDpiAwareness function.RRUZ
@RRUZ The documentation recommends that this is set in the manifest rather than using this function. This function exists for scenarios where manifesting the option is not possible.David Heffernan
@DavidHeffernan, I know about that, but I experienced some issues using the manifest approach. So I ended using this function since Windows 8.1 and works just fine.RRUZ
@RRUZ The manifest works perfectly well. You must have got something wrong.David Heffernan

1 Answers

2
votes

It turned out that the problem is not caused by the application not responding to DPI change. It actually does not even matter, if the application was running when the DPI changed.

The root cause is that when the DPI is changed during the Windows session, only a per-monitor DPI changes (even on a single monitor system). A system (legacy) DPI is not updated.

So when you run an application, that does not declare per-monitor-DPI awareness, and that relies on the system DPI, it runs as if the DPI did not change. But the system scales its windows pixel-wise to the new DPI.

It's only after logoff/logon that the system DPI aligns with the monitor DPI.


A solution is to declare the support in an application manifest by setting dpiAwareness to PerMonitorV2 (and additional PerMonitor value and set dpiAware to True/PM for backward compatibility with older Windows 10 builds and Windows 8.1):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    ...
    <asmv3:application>
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <dpiAware>True/PM</dpiAware>
            <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
        </asmv3:windowsSettings>
    </asmv3:application>
</assembly>

And the application window scaling has to be reimplemented to use new GetDpiForMonitor WinAPI function instead of the legacy GetDeviceCaps(DC, LOGPIXELSX/LOGPIXELSY).