Combining Windows manifest gdiScaling and CEF4Delphi
Posted: Mon Jul 02, 2018 2:00 pm
Hi,
We have an application that still isn't High-DPI compliant - we're still on XE6 for production.
Planning to port the code to Delphi Tokyo 10.2 and have a project to try an be High DPI-compliant.
Right now the production version declares dpiAware=false in the application's manifest file. This ensures that Windows does a kind of bitmap-rescaling of windows and contents when rendering on monitors with > 100% font scaling enabled.
This works - including CEF windows, but the result is fuzzy.
Now with recent versions of Windows 10 they support something they call GDI scaling. The application can keep old non-DPI aware GDI code, but the Windows OS automatically scales GDI calls for you, resulting in much more accurate scaling of windows and contents, giving a much crisper result.
Now, this works fine for all windows in the application - except for the CEF windows.
When Windows does the scaling, it increases the effective size of the windows, but it leaves non-GDI windows (like DirectDraw/DirectWrite that I think CEF/Chromium uses) alone. The end result is that the Delphi parent window becomes correct size (big), while the CEF child window becomes too small, and is positioned wrong. Example:
https://www.dropbox.com/s/jt097aw5x27nc ... n.png?dl=0
We have tried different workarounds, including:
1. Calling new API SetThreadDpiAwarenessContext to override DPI-awareness for the both the Delphi parent window and the TCEFWindowParent instance - no effect. Sample code:
2. Experimenting with changing the size of the ChildWindowHandle window, by modifying the existing code in:
I know there is a EnableHighDPISupport property in TCefApplication, but the only thing this does it to programatically set the equivalent dpiAware=True in the application manifest file.
Example manifest file snippet:
Dynamic API import-code for SetThreadDpiAwarenessContext:
Background info:
https://docs.microsoft.com/en-us/window ... plications
https://blogs.windows.com/buildingapps/ ... lDZvwy0.97
Does anyone have any experience with this or suggestions on how it is possible to get GDI Scaling to work, while getting the right position and size of the CEF windows?
/Hallvard
We have an application that still isn't High-DPI compliant - we're still on XE6 for production.
Planning to port the code to Delphi Tokyo 10.2 and have a project to try an be High DPI-compliant.
Right now the production version declares dpiAware=false in the application's manifest file. This ensures that Windows does a kind of bitmap-rescaling of windows and contents when rendering on monitors with > 100% font scaling enabled.
This works - including CEF windows, but the result is fuzzy.
Now with recent versions of Windows 10 they support something they call GDI scaling. The application can keep old non-DPI aware GDI code, but the Windows OS automatically scales GDI calls for you, resulting in much more accurate scaling of windows and contents, giving a much crisper result.
Now, this works fine for all windows in the application - except for the CEF windows.
When Windows does the scaling, it increases the effective size of the windows, but it leaves non-GDI windows (like DirectDraw/DirectWrite that I think CEF/Chromium uses) alone. The end result is that the Delphi parent window becomes correct size (big), while the CEF child window becomes too small, and is positioned wrong. Example:
https://www.dropbox.com/s/jt097aw5x27nc ... n.png?dl=0
We have tried different workarounds, including:
1. Calling new API SetThreadDpiAwarenessContext to override DPI-awareness for the both the Delphi parent window and the TCEFWindowParent instance - no effect. Sample code:
Code: Select all
TCEFWindowParent = class(TWinControl)
protected
procedure CreateHandle; override;
...
procedure TCEFWindowParent.CreateHandle;
var
PrevDpiContext: DPI_AWARENESS_CONTEXT;
begin
PrevDpiContext := 0;
if (WindowHandle = 0) and Assigned(SetThreadDpiAwarenessContext) then
PrevDpiContext := SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
inherited;
if PrevDpiContext <> 0 then
SetThreadDpiAwarenessContext(PrevDpiContext);
end;
Code: Select all
procedure TCEFWindowParent.UpdateSize;
var
TempRect : TRect;
hdwp: THandle;
TempHandle : THandle;
begin
TempHandle := ChildWindowHandle;
if (TempHandle = 0) then Exit;
TempRect := GetClientRect;
//TempRect.Width := TempRect.Width * 2; // - no effect
//TempRect.Height := TempRect.Height * 2; // - no effect
hdwp := BeginDeferWindowPos(1);
try
hdwp := DeferWindowPos(hdwp, TempHandle, 0,
TempRect.left, TempRect.top, TempRect.right - TempRect.left, TempRect.bottom - TempRect.top,
SWP_NOZORDER);
finally
EndDeferWindowPos(hdwp);
end;
end;
Example manifest file snippet:
Code: Select all
<asmv3:application>
<asmv3:windowsSettings >
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">false</dpiAwareness>
<gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">true</gdiScaling>
</asmv3:windowsSettings>
</asmv3:application>
Code: Select all
type
DPI_AWARENESS_CONTEXT = type THandle;
const
DPI_AWARENESS_CONTEXT_UNAWARE = DPI_AWARENESS_CONTEXT(-1);
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = DPI_AWARENESS_CONTEXT(-2);
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = DPI_AWARENESS_CONTEXT(-3);
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = DPI_AWARENESS_CONTEXT(-4);
var
SetThreadDpiAwarenessContext: function (dpiContext: DPI_AWARENESS_CONTEXT): DPI_AWARENESS_CONTEXT; stdcall;
procedure LoadDpiAPI;
var
User32Handle: HMODULE;
begin
// my bolted-on dpi fix for Windows 10 anniversary+
User32Handle := GetModuleHandle('User32.dll');
if User32Handle > HINSTANCE_ERROR then
SetThreadDpiAwarenessContext := GetProcAddress(User32Handle, 'SetThreadDpiAwarenessContext');
end;
https://docs.microsoft.com/en-us/window ... plications
https://blogs.windows.com/buildingapps/ ... lDZvwy0.97
Does anyone have any experience with this or suggestions on how it is possible to get GDI Scaling to work, while getting the right position and size of the CEF windows?
/Hallvard