Some of my customers want to be able to scale my application manually (when Windows dpi is set to 96), so I had to implement scaling. Unfortunately these customers cannot go wit
Thanks to Sertac Akyuz I found a solution to my problem. In the Initialization part of the unit containing the scaling code I can switch between DPI-Awareness and Non-DPI-Awareness. It is important not to have this setting in the application manifest, which can be achieved by supplying a custom manifest like this (use control decoration and run with rights of current user):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="*"/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
This is the actual code switching depending on a registry key:
// Set DPI Awareness depending on a registry setting
with TRegIniFile.create('SOFTWARE\' + SRegName) do
begin
setting := readInteger('SETTINGS', 'scale', 0);
Free;
end;
handle := LoadLibrary('shcore.dll');
if handle <> 0 then
begin
setProcessDPIAwareness := GetProcAddress(handle, 'SetProcessDpiAwareness');
if Assigned(setProcessDPIAwareness) then
begin
if setting < 2 then
// setting <2 means no scaling vs Windows
setProcessDPIAwareness(0)
else
// setting 2: 120%, 3: 140% vs. Windows
// The actual used scaling factor multiplies by windows DPI/96
setProcessDPIAwareness(1);
end;
FreeLibrary(handle);
// Get windows scaling as Screen.PixelsPerInch was read before swiching DPI awareness
// Our scaling routines now work with WinDPI instead of Screen.PixelsPerInch
WinDPI:= Screen.MonitorFromWindow(application.handle).PixelsPerInch;
end;
The last line of this snippet retrieves the current DPI for the current monitor as screen.pixelsperinch seems to be initialized before and does always return 96 as for a non dpi aware application. I use the value of winDPI in all subsequent scaling calculations and it works perfect.