Delphi High DPI switches between its zoom and Windows scales

Some of my customers want to be able to manually extend my application (when the Windows dpi is set to 96), so I have to implement the extension. Unfortunately, these customers cannot set the Windows DPI For other values ​​and let WIndows extend my application because some very important applications they use do not perform well at resolution <> 96 DPI.

I managed to make me The Delphi 10.1 application scale is quite good, even at 200%, but the higher the factor, some proportions become “not so good-looking”. Many third-party components require special scaling processing, and even this cannot be scaled 100% accurately. Although The app scaled by window looks a bit blurry in high resolution, but all scales are 100% accurate, and the app looks more professional.

So I asked myself if it is possible to create a setting , Allows to tell Windows to use the extension as the default setting, and if the customer wants the extension to be different from the current Windows extension, they can only extend it themselves. This setting is hosted in the Windows manifest of the executable file that is read when the application starts. Is there a way? Change it at runtime (early launch of the application)? Creating two executable files with different manifests is definitely not a good solution.

Thank you for your help

Thanks to Sertac Akyuz, I found a solution to the problem. In the initialization section of the unit containing the scaling code, I can switch between DPI-Awareness and Non-DPI-Awareness. Important Do not set this setting in the application manifest. This can be achieved by providing such a custom manifest (modified with controls and run with the permissions of the current user):

< pre>



type=”win32″
name=”Microsoft.Windows.Common-Controls”
version =”6.0.0.0″
publicKeyToken=”6595b64144ccf1df”
language=”*”
processorArchitecture=”*”/>




level=” asInvoker”
uiAccess=”false”/>


This is based on the actual code switching of the 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< br /> // Our scaling routines now work wit h WinDPI instead of Screen.PixelsPerInch
WinDPI:= Screen.MonitorFromWindow(application.handle).PixelsPerInch;
end;

The last line of this fragment retrieves the current DPI of the current monitor The screen.pixelsperinch seems to be initialized before and always returns 96, just like non-dpi-aware applications. I use the value of winDPI in all subsequent zoom calculations and it works flawlessly.

Some of my customers want to be able to manually extend my application (when the Windows dpi is set to 96), so I have to implement the extension. Unfortunately, these customers cannot set the Windows DPI to other values ​​and let Windows Extend my application because some very important applications they use do not perform well at resolution <> 96 DPI.

I managed to scale my Delphi 10.1 application Quite good, even at 200%, but the higher the factor, some proportions become “not pretty”. Many third-party components require special scaling processing, and even this cannot be scaled 100% accurately. Although the application is scaled by window It looks a bit blurry at high resolutions, but all proportions are 100% accurate, and the application looks more professional.

So I asked myself if it is possible to create a setting that allows to tell Windows to expand As a default setting, and if the customer wants the extension to be different from the current Windows extension, they can only extend it themselves. This setting is hosted in the Windows manifest of the executable file that is read when the application starts. Is there a way to change it at runtime (app Early start of the program)? Creating two executable files with different manifests is definitely not a good solution.

Thank you for your help

Thanks to Sertac Akyuz , I found a solution to the problem. In the initialization section of the unit containing the scaling code, I can switch between DPI-Awareness and Non-DPI-Awareness. It is important not to set this setting in the application manifest, this This can be achieved by providing such a custom manifest (modified with controls and run with the permissions of the current user):





type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken= "6595b64144ccf1df"
language="*"
processorArchitecture="*"/>





level="asInvoker"
uiAccess="false"/ >



This is based on the actual code switching of the 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 of the current monitor as screen.pixelsperinch seems to be initialized before and always returns 96 , Just like a non-dpi-aware application. I use the value of winDPI in all subsequent scaling calculations and it works perfectly.

Leave a Comment

Your email address will not be published.