Reputation: 202088
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.
Upvotes: 1
Views: 495
Reputation: 202088
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)
.
Upvotes: 2