通过外部窗口从GetWindowRect获取DPI识别正确的RECT

时间:2011-11-09 04:16:24

标签: windows winapi visual-c++

我正在制作应用程序DPI Aware但我需要在其他应用程序的HWND上执行GetWindowRect。我的问题是这也适用于也是DPI Aware的应用程序,但我如何检测HWND句柄是否是DPI虚拟化的,例如缩放所以我可以自己缩放它?或者是否有其他我错过的API,它将以DPI识别的方式从另一个进程的HWND中获取窗口的大小?

我尝试了LogicalToPhysicalPoint,但似乎总是失败,可能是因为HWND不属于我的应用程序。

2 个答案:

答案 0 :(得分:6)

这不是一个实际问题。如果您将流程标记为具有高DPI感知能力,那么系统将不再执行任何类型的DPI虚拟化,并且API将不再向您提供有关实际值的信息。

特别是,如果您从高DPI感知应用程序中调用GetWindowRectGetClientRect,您将获得屏幕坐标中的实际值。这不仅适用于属于应用程序进程的窗口,也适用于属于其他进程的窗口,无论其他进程的DPI感知设置如何。

从Windows 8.1起,PhysicalToLogicalPointLogicalToPhysicalPoint功能不再是必需的,实际上并没有做任何事情。这两个函数的文档明确地说明了这一点:

  

在Windows 8.1中,系统和进程间通信的额外虚拟化意味着对于大多数应用程序,您不需要这些API。因此,在Windows 8.1中,PhysicalToLogicalPointLogicalToPhysicalPoint不再转换点。系统将所有点返回到自己坐标空间中的应用程序。

最后一句话只是表达我上面所说的不同方式。 系统根据调用者的DPI感知返回值。如果您的进程具有高DPI感知能力,那么您将获得实际值。您不需要自己缩放值。如果你不是高DPI意识,那么你可能会被骗到实际值。但这是有道理的,因为假设你无法处理真相而且不会做出适当的反应。

为了清楚起见,我应该指出,现在实际上有两个级别的高DPI感知,从Windows 8.1开始(并在Windows 10中继续):

  1. 第一个层次是Windows Vista引入的高DPI感知。这由应用程序的清单文件中的true设置表示,它只是意味着您(应用程序)能够处理设置为除此之外的其他内容的系统 DPI经典默认值为96 DPI。

    基于以上知识,我们知道如果具有此DPI感知设置的进程调用返回屏幕坐标的API函数,它将根据系统DPI接收值。

  2. 然后在Windows 8.1中引入了 per-monitor 高DPI感知的新级别。这由应用程序清单中的True/PM设置表示,这意味着您(应用程序)能够处理具有不同DPI设置的不同监视器。换句话说,虽然仍然存在系统默认DPI(并且它可能是96 DPI或者可能是其他东西),但是可能存在连接到系统的监视器,其使用不同的DPI设置(除系统DPI之外的其他设置)。

    同样,基于上述理解,我们知道如果每个监视器高DPI感知的进程调用返回屏幕坐标的API函数,它将接收相对于包含监视器的DPI的实际坐标有问题的窗口。

  3. 如果您的进程完全不支持DPI(清单中没有设置,或false),那么当您调用返回屏幕坐标的API函数时,您将收到基于系统缩放/虚拟化的坐标全DPI为96 DPI。

答案 1 :(得分:0)

DPI感知标志设置在应用程序级别而不是窗口级别因此,如果您能够获取其他应用程序的特定窗口句柄的进程,那么您可以使用GetProcessDpiAwareness()函数来获取dpi感知标志该特定流程请参阅此microsoft文档https://msdn.microsoft.com/en-us/library/windows/desktop/dn302113(v=vs.85).aspx