如何知道 Windows HWND 的当前 bitmap-scaling 因子?
How to know current bitmap-scaling factor for a Windows HWND?
我有一个 C# 小程序,HelloCs.cs,像这样:
using System;
using System.Drawing;
using System.Windows.Forms;
class HelloWorld: Form
{
public static void Main()
{
Application.Run(new HelloWorld());
}
public HelloWorld()
{
Text = "Hello World";
BackColor = Color.White;
}
protected override void OnPaint(PaintEventArgs pea)
{
Graphics grfx = pea.Graphics;
this.Width = 200;
this.Height = 100;
grfx.DrawString(
$"({this.Width} , {this.Height}) Hello, Windows Forms!",
Font, Brushes.Black, 0, 0);
base.OnPaint(pea);
}
}
== 案例 1.0 ==
在默认 Windows 7 系统上 运行 时。显示是这样的,没什么特别的:
window 宽度和高度分别为 200 和 100。
== 案例 1.5 ==
当我将系统 DPI 缩放设置为 150%(并重新启动 OS)时,C# 程序仍然像以前一样报告 window 宽度和高度,但是 window 的实际值on-screen size(pixel count) 变成了 300 和 150。也就是说,Windows 系统已经在我的 window.
那么我的问题是:我怎么知道(在我自己的程序中,或使用 HWND 句柄),系统是否已将 bitmap-scaling 应用到 window,以及缩放比例是多少因子。
在Window 10上,事情变得更加复杂,因为Windows 10可能根据HWND的当前驻留监视器对不同的HWND应用不同的比例因子。
我希望得到一个适用于 Windows 7 和 10 的答案。
经过一个月的调查,我发现这是一个非常复杂的问题。 Windows7、Windows8.1和Win10.1607+的情况都不一样
最后,我设法编写了一个可以由系统确定位图拉伸因子的演示程序(基于一个开源项目)。
说话很便宜,所以这是我的工作代码:
https://github.com/chjfth/window-finder-control
特征:
- 在Windows 7 和 Win10.1607+ 上,无论调用程序本身是 DPI-unaware、SysDpi-aware 还是 Per-monitor-aware,我都能准确判断。
- 在 Windows 8.1 ~ Win10.1511 上,调用程序 必须 Per-monitor-aware 才能准确地告诉它。这是因为缺少 API 对 Win81 基本混合模式 DPI 缩放的支持。
查看下面的演示 UI
图 1:
解释:
- WinRect通过调用
GetWindowRect
显示RECT值,所谓虚拟RECT大小。
- 左上角的红色数字显示目标的物理尺寸 window 由调用程序“计算或推断”。
它们都是 400x241,所以 target-window 不是位图拉伸的。
图 2:在 Windows7 上,全局 DPI 缩放设置为 150%,物理 RECT 比虚拟 RECT 大 150%(宽度或高度比较,宽度 600 vs 400)。因此,目标 windows 拉伸了 150%。
图 3:在 Win10.1909 上,我们还可以看到 150% 位图拉伸 window。
图4:在Win10.1909上,我们甚至可以看到位图缩小的HWND。当调用者是 SysDpi-aware(150%) 时会发生这种情况,并且目标-windows 也是 SysDpi-aware 但驻留在 100%-缩放监视器上。
我有一个 C# 小程序,HelloCs.cs,像这样:
using System;
using System.Drawing;
using System.Windows.Forms;
class HelloWorld: Form
{
public static void Main()
{
Application.Run(new HelloWorld());
}
public HelloWorld()
{
Text = "Hello World";
BackColor = Color.White;
}
protected override void OnPaint(PaintEventArgs pea)
{
Graphics grfx = pea.Graphics;
this.Width = 200;
this.Height = 100;
grfx.DrawString(
$"({this.Width} , {this.Height}) Hello, Windows Forms!",
Font, Brushes.Black, 0, 0);
base.OnPaint(pea);
}
}
== 案例 1.0 ==
在默认 Windows 7 系统上 运行 时。显示是这样的,没什么特别的:
window 宽度和高度分别为 200 和 100。
== 案例 1.5 ==
当我将系统 DPI 缩放设置为 150%(并重新启动 OS)时,C# 程序仍然像以前一样报告 window 宽度和高度,但是 window 的实际值on-screen size(pixel count) 变成了 300 和 150。也就是说,Windows 系统已经在我的 window.
那么我的问题是:我怎么知道(在我自己的程序中,或使用 HWND 句柄),系统是否已将 bitmap-scaling 应用到 window,以及缩放比例是多少因子。
在Window 10上,事情变得更加复杂,因为Windows 10可能根据HWND的当前驻留监视器对不同的HWND应用不同的比例因子。
我希望得到一个适用于 Windows 7 和 10 的答案。
经过一个月的调查,我发现这是一个非常复杂的问题。 Windows7、Windows8.1和Win10.1607+的情况都不一样
最后,我设法编写了一个可以由系统确定位图拉伸因子的演示程序(基于一个开源项目)。
说话很便宜,所以这是我的工作代码: https://github.com/chjfth/window-finder-control
特征:
- 在Windows 7 和 Win10.1607+ 上,无论调用程序本身是 DPI-unaware、SysDpi-aware 还是 Per-monitor-aware,我都能准确判断。
- 在 Windows 8.1 ~ Win10.1511 上,调用程序 必须 Per-monitor-aware 才能准确地告诉它。这是因为缺少 API 对 Win81 基本混合模式 DPI 缩放的支持。
查看下面的演示 UI
图 1:
解释:
- WinRect通过调用
GetWindowRect
显示RECT值,所谓虚拟RECT大小。 - 左上角的红色数字显示目标的物理尺寸 window 由调用程序“计算或推断”。
它们都是 400x241,所以 target-window 不是位图拉伸的。
图 2:在 Windows7 上,全局 DPI 缩放设置为 150%,物理 RECT 比虚拟 RECT 大 150%(宽度或高度比较,宽度 600 vs 400)。因此,目标 windows 拉伸了 150%。
图 3:在 Win10.1909 上,我们还可以看到 150% 位图拉伸 window。
图4:在Win10.1909上,我们甚至可以看到位图缩小的HWND。当调用者是 SysDpi-aware(150%) 时会发生这种情况,并且目标-windows 也是 SysDpi-aware 但驻留在 100%-缩放监视器上。