2021年12月21日 星期二

high DPI displays standard-DPI displays

 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対応)

沒有留言: