high DPI displays
standard-DPI displays
https://docs.microsoft.com/zh-tw/windows/uwp/get-started/universal-application-platform-guide
Windows Universal Platform (UWP)
https://docs.microsoft.com/zh-tw/archive/blogs/askcore/display-scaling-in-windows-10
Display Scaling in Windows 10
display scale factor scale factor
display scaling is > 100% “System DPI Awareness.” System DPI Awareness
https://docs.microsoft.com/zh-tw/archive/blogs/askcore/display-scaling-changes-for-the-windows-10-anniversary-update
Display Scaling changes for the Windows 10 Anniversary Update
https://docs.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-setthreaddpiawarenesscontext?redirectedfrom=MSDN
SetThreadDpiAwarenessContext function (winuser.h)
Classic desktop applications scaled to 100%, 125%, 150%, 200% and 250%; Store apps scaled to 100%, 140% and 180%. As a result, when running different apps side by side in productivity scenarios,
~450% 23” 8K desktop
applications to dynamically scale and where Windows was limited in this regard. One of the main lessons learned was that, even for simple applications, the model of registering an application as being either System DPI Aware or Per-Monitor-DPI Aware
https://docs.microsoft.com/zh-tw/windows/win32/dlgbox/common-dialog-box-library?redirectedfrom=MSDN
(ComDlg32, for example Common Item Dialog ) that didn’t scale on a per-DPI basis.
DPI_AWARENESS_CONTEXT and the SetThreadDpiAwarenessContext API
DPI _ 感知 _ 內容控制碼 https://docs.microsoft.com/zh-tw/windows/win32/hidpi/dpi-awareness-context
SetThreadDpiAwarenessContext function (winuser.h)
The old DPI_AWARENESS_CONTEXT for the thread.
If the dpiContext is invalid,
the thread will not be updated and the return value will be NULL ...
https://docs.microsoft.com/zh-tw/windows/win32/hidpi/wm-dpichanged-beforeparent
https://docs.microsoft.com/zh-tw/windows/win32/hidpi/wm-getdpiscaledsize
WM_DPICHANGE message
https://docs.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-setwindowpos?redirectedfrom=MSDN
SetWindowPos function (winuser.h)
EnableNonClientDpiScaling API to get Notepad’s non-client area to automatically DPI scale properly.
https://docs.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-enablenonclientdpiscaling?redirectedfrom=MSDN
WM_NCCREATE
https://docs.microsoft.com/zh-tw/windows/win32/api/winuser/nf-winuser-getdpiforwindow?redirectedfrom=MSDN
GetDpiForWindow function (winuser.h)
FontStruct.lfHeight = -MulDiv(iPointSize, GetDpiForWindow(hwndNP), 720);
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms646914(v=vs.85)?redirectedfrom=MSDN
ChooseFont dialog was not per-monitor DPI aware
DPI_AWARENESS_CONTEXT previousDpiContext = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
BOOL cfResult = ChooseFont(cf);
SetThreadDpiAwarenessContext(previousDpiContext);
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
DPI_AWARENESS_CONTEXT_UNAWARE
FontStruct.lfHeight = -MulDiv(cf.iPointSize, GetDpiForWindow(hwndNP), 720);
SetThreadDpiAwarenessContext
DPI_AWARENESS_CONTEXT
AdjustWindowRectExForDpi
GetDpiForSystem
GetDpiForWindow
GetSystemMetricForDpi
SystemParametersInfoForDpi
GetDpiForSystem GetDC GetDeviceCaps
EnableNonClientDpiScaling
SetThreadDpiAwarenessContext
https://github.com/Microsoft/Windows-classic-samples/tree/main/Samples/DPIAwarenessPerWindow
https://docs.microsoft.com/zh-tw/windows/win32/hidpi/high-dpi-improvements-for-desktop-applications?redirectedfrom=MSDN
https://blogs.windows.com/windowsdeveloper/2016/10/24/high-dpi-scaling-improvements-for-desktop-applications-and-mixed-mode-dpi-scaling-in-the-windows-10-anniversary-update/
https://blogs.windows.com/windowsdeveloper/2017/05/19/improving-high-dpi-experience-gdi-based-desktop-apps/
Improving the high-DPI experience in GDI based Desktop Apps
https://docs.microsoft.com/zh-tw/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows?redirectedfrom=MSDN
Manifest File
The most common way to declare an application as DPI aware is through the application manifest file. There are two settings that you can use - <dpiAware> and <dpiAwareness>. Here is a small table that describes the different states that you can use with each setting.
DPI Mode <dpiAware> <dpiAwareness>
<description>Microsoft Management Console</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="highestAvailable"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">
<gdiScaling>true</gdiScaling>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
ode Sample:
[code lang=”csharp”]
LRESULT WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
…
case WM_PAINT:
{
PAINTSTRUCT ps;
// Get a paint DC for current window.
// Paint DC contains the right scaling to match
// the monitor DPI where the window is located.
HDC hdc = BeginPaint(hWnd, &ps);
RECT rect;
GetClientRect(hDlg, &rect);
UINT cx = (rect.right – rect.left);
UITN cy = (rect.bottom – rect.top);
// Create a compatible bitmap using paint DC.
// Compatible bitmap will be properly scaled in size internally and
// transparently to the app to match current monitor DPI where
// the window is located.
HBITMAP memBitmap = CreateCompatibleBitmap(hdc, cx, cy);
// Create a compatible DC, even without a bitmap selected,
// compatible DC will inherit the paint DC GDI scaling
// matching the window monitor DPI.
HDC memDC = CreateCompatibleDC(hdc);
// Selecting GDI scaled compatible bitmap in the
// GDI scaled compatible DC.
HBTIMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
// Setting some properties in the compatible GDI scaled DC.
SetTextColor(memDC, GetSysColor(COLOR_INFOTEXT));
SetBkMode(memDC, TRANSPARENT);
SelectObject(memDC, g_hFont);
// Drawing content on the compatible GDI scaled DC.
// If the monitor DPI was 150% or 200%, text internally will
// be draw at next integral scaling value, in current example
// 200%.
DrawText(memDC, ctx.balloonText, -1, &rect,
DT_NOCLIP | DT_LEFT | DT_NOPREFIX | DT_WORDBREAK);
// Copying the content back from compatible DC to paint DC.
// Since both compatible DC and paint DC are GDI scaled,
// content is copied without any stretching thus preserving
// the quality of the rendering.
BitBlt(hdc, 0, 0, cx, cy, memDC, 0, 0);
// Cleanup.
SelectObject(memDC, oldBitmap);
DeleteObject(memBitmap);
DeleteDC(memDC);
// At this time the content is presented to the screen.
// DWM (Desktop Window Manager) will scale down if required the
// content to actual monitor DPI.
// If the monitor DPI is already an integral one, for example 200%,
// there would be no DWM down scaling.
// If the monitor DPI is 150%, DWM will scale down rendered content
// from 200% to 150%.
// While not a perfect solution, it’s better to scale-down content
// instead of scaling-up since a lot of the details will be preserved
// during scale-down.
// The end result is that with GDI Scaling enabled, the content will
// look less blurry on screen and in case of monitors with DPI setting
// set to an integral value (200%, 300%) the vector based and text
// content will be rendered natively at the monitor DPI looking crisp
// on screen.
EndPaint(hWnd, &ps);
}
break;
…
}
}
[/code]
<?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>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
Native API
There are three native API calls that can set awareness now:
SetProcessDpiAware - Windows Vista or later
SetProcessDpiAwareness - Windows 8.1 or later
SetProcessDpiAwarenessContext - Windows 10, version 1607 or later
The latest API offers PerMonitorV2 support, so it is the currently recommend one.
https://www.telerik.com/blogs/winforms-scaling-at-large-dpi-settings-is-it-even-possible-
New events for handling dynamic DPI changes – DpiChanged, DpiChangedAfterParent, DpiChangedBeforeParent.
New methods – DeviceDpi, ScaleBitmapLogicalToDevice, LogicalToDeviceUnits.
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ivate void workbookTestButton_Click(object sender, EventArgs e)
{
SetProcessDpiAwareness(_Process_DPI_Awareness.Process_DPI_Unaware);
Workbook wb = new Workbook();
}
[DllImport("shcore.dll")]
static extern int SetProcessDpiAwareness(_Process_DPI_Awareness value);
enum _Process_DPI_Awareness
{
Process_DPI_Unaware = 0,
Process_System_DPI_Aware = 1,
Process_Per_Monitor_DPI_Aware = 2
}
Delphi VCL Applications with mixed DPI
https://www.uweraabe.de/Blog/2021/08/28/delphi-vcl-applications-with-mixed-dpi/
add a second VCL form to the application and drop some controls on to it, so we can distinguish the form instances by its display quality on a high DPI monitor. I just assume that the second form class is named TForm2.
Now we get back to the first form and drop two buttons on the form and double click each to fill their event handlers. The first button gets the single line:
procedure TForm1.Button1Click(Sender: TObject);
begin
TForm2.Create(Self).Show;
end;
Make sure that the unit containing TForm2 is added to the uses clause.
The OnClick event of the second button needs a bit more code:
procedure TForm1.Button2Click(Sender: TObject);
var
previousDpiContext: DPI_AWARENESS_CONTEXT;
myForm: TForm;
begin
previousDpiContext := SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
try
myForm := TForm2.Create(Self);
finally
SetThreadDpiAwarenessContext(previousDpiContext);
end;
myForm.Show;
end;
So we temporarily change the DPI awareness of the current thread to unaware, create the form and restore the context to its previous state before finally showing the form.
https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-improvements-for-desktop-applications
https://question-it.com/questions/736123/kak-konvertirovat-declare_handle-i-posledujuschie-konstanty-iz-windefh-v-delphi
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
NativeUInts:
DPI_AWARENESS_CONTEXT_UNAWARE = 16;
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = 17;
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = 18;
SetThreadDpiAwarenessContext
https://docs.microsoft.com/zh-tw/windows/win32/hidpi/setting-the-default-dpi-awareness-for-a-process
https://github.com/MicrosoftDocs/visualstudio-docs.zh-tw/blob/live/docs/extensibility/addressing-dpi-issues2.md
https://docs.microsoft.com/zh-tw/visualstudio/extensibility/addressing-dpi-issues2?view=vs-2022
https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.visualstudio.platformui.dpihelper?view=visualstudiosdk-2022
https://www.visualstudioextensibility.com/2015/02/01/visual-studio-extensions-and-dpi-awareness/
Winapi.MultiMon.MonitorFromPoint GetDpiForMonitor GetScaleFactorForMonitor delphi
https://www.sql.ru/forum/1317197/getscalefactorformonitor-nevernoe-znachenie
procedure CallSetProcessDPIAware;
var
SetProcessDPIAware: function: Boolean; stdcall;
H: THandle;
begin
H := GetModuleHandle('User32.dll');
if H > 0 then
begin
@SetProcessDPIAware := GetProcAddress(H, 'SetProcessDPIAware');
if Assigned(SetProcessDPIAware) then
SetProcessDPIAware();
end;
end;
http://yamatyuu.net/computer/program/vc2013/gmonitorinfo/index.html
WMIを使用してディスプレイサイズ,接続方法を取得(Windows 10高DPI対応)
沒有留言:
張貼留言