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

Kar*_*all 13 windows winapi visual-c++

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

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

Cod*_*ray 6

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

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

作为Windows 8.1中的,在PhysicalToLogicalPointLogicalToPhysicalPoint功能不再是必要的,实际上没有做任何事情.这两个函数的文档明确地将其调用:

在Windows 8.1中,系统的额外虚拟化和进程间通信意味着对于大多数应用程序而言,您不需要这些API.其结果是,在Windows 8.1,PhysicalToLogicalPoint并且LogicalToPhysicalPoint不再转换点.系统将所有点返回到其自己的坐标空间中的应用程序.

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

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

  1. 在Windows Vista中引入了第一级,具有高DPI感知能力.这是通过设置显示true在应用程序的清单文件,它只是意味着你(应用程序)能够应对系统 DPI被设置为96 DPI经典的默认以外的东西.

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

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

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

如果您的进程根本不知道DPI(清单中没有设置,或者false),那么当您调用返回屏幕坐标的API函数时,您将收到基于系统范围DPI为96 DPI的缩放/虚拟化坐标.

  • 我认为你是对的,系统根据调用者的 DPI 感知返回值。但是,如果使用 dpiAware=true,当有多个屏幕时,您将无法获得真实值。在第一种情况下,Windows 仍会缩放非主屏幕以匹配主屏幕。您需要 dpiAware=true/PM。 (2认同)

Mak*_*Mak 0

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