2011-11-09 806 views
12

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

我试过LogicalToPhysicalPoint,但总是看起来失败,可能是因为HWND不属于我的应用程序。

+1

我觉得很难相信'GetWindowRect'返回值取决于其他应用程序是否被虚拟化。这是真的吗?你是在问一个顶级窗口还是一个子窗口?你在做什么? –

+2

其实我自己也是这样做的,我必须用DWMWA_EXTENDED_FRAME_BOUNDS作为参数来调用DwmGetWindowAttribute。是的,它的行为就像这样,很容易复制,创建一个DPI感知应用程序,将您的DPI设置为> 144并尝试。从某种意义上说,我认为这样做是有道理的,因为虚拟化窗口没有意识到它正在被虚拟化,并且这些值大多数来自窗口所属进程的上下文。 –

+5

我认为这个问题应该重新打开 - 我不同意关闭的理由。截至目前,戴尔已经开始出货带有高分辨率显示器的新型戴尔XPS设备。这使得这个问题与许多在Windows上编写代码的开发人员相关。一旦开始在Windows中使用高分辨率显示器,大多数应用程序看起来很糟糕。在这个地区附近有更多的社区投入,我们都可以通过这个新的雷区更快地获得。 –

回答

4

这不是一个实际问题。如果您将流程标记为支持高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来指示,它仅表示您(应用程序)能够处理设置为经典默认设置96 DPI以外的DPI的系统

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

  2. 然后有新的级别,与Windows 8.1引入的每个显示器高DPI的意识。这通过应用程序清单中的设置True/PM来指示,这意味着您(应用程序)能够处理具有不同DPI设置的不同监视器。换句话说,尽管仍然存在系统默认的DPI(可能是96 DPI,或者它可能是其他设备),但可能会有连接到系统的显示器使用不同的DPI设置(系统DPI以外的其他设置)。

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

如果过程没有DPI意识到在所有(在清单中没有设置或false),那么当你调用返回屏幕坐标的API函数,您将收到的坐标调整/虚拟化体系为基础96 DPI的全新DPI。

+0

“您将收到根据96 DPI的系统范围DPI缩放/虚拟化的坐标。” - 或者系统dpi设置为什么。 – johnathon

+0

我认为你是正确的,系统根据来电者的DPI意识返回值。但是,如果您使用dpiAware = true,则当您有多个屏幕时,您将无法获得真实值。在第一种情况下,Windows仍会缩放非主屏幕以匹配主屏幕。您需要有dpiAware = true/PM。 –