如何知道 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%-缩放监视器上。