【问题标题】:Getting an DPI aware correct RECT from GetWindowRect from a external window从外部窗口的 GetWindowRect 获取 DPI 感知正确的 RECT
【发布时间】:2011-12-25 00:10:36
【问题描述】:

我正在制作应用程序 DPI Aware,但我需要对来自其他应用程序的 HWND 执行GetWindowRect。我的问题是这在也支持 DPI 感知的应用程序上运行良好,但我如何检测 HWND 句柄是否是 DPI 虚拟化的,例如缩放所以我可以自己缩放它?或者是否有其他我错过的 API 可以让我以 DPI 感知方式从另一个进程的 HWND 获得窗口大小?

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

【问题讨论】:

  • 我很难相信GetWindowRect 返回的值取决于其他应用程序是否被虚拟化。真的是这样吗?你要的是顶层窗口还是子窗口的矩形?你用这个矩形做什么?
  • 其实是我自己解决的,我必须以 DWMWA_EXTENDED_FRAME_BOUNDS 作为参数调用 DwmGetWindowAttribute。是的,它的行为确实像这样,很容易复制,创建一个 DPI 感知应用程序,将您的 DPI 设置为 >144 并尝试它。我想在某种意义上这样做是有意义的,因为虚拟化的窗口没有意识到它正在被虚拟化,并且大多数值来自窗口所属进程的上下文。
  • 我认为这个问题应该重新打开——我不同意关闭的原因。截至目前,戴尔开始出货具有高 dpi 显示器的新戴尔 XPS 机器。这使得这个问题与许多在 Windows 上编写代码的开发人员相关。一旦您开始在 Windows 上使用高 dpi 显示器,大多数应用程序看起来都很糟糕。社区对这一地区的投入越多,我们就能越快通过这个新的雷区。

标签: windows winapi visual-c++


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这不是一个实际问题。如果您将您的流程标记为高 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 引入的新级别,即 每显示器 高 DPI 感知。这由应用程序清单中的True/PM 设置指示,这意味着您(应用程序)能够处理具有不同 DPI 设置的不同监视器。换句话说,虽然仍然有系统默认 DPI(可能是 96 DPI 或其他),但可能有连接到系统的显示器使用不同的 DPI 设置(系统 DPI 以外的其他设置)。

      再一次,基于上述理解,我们知道如果一个具有per-monitor high-DPI感知的进程调用一个返回屏幕坐标的API函数,它将接收到相对于包含的显示器的DPI的实际坐标有问题的窗口。

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

    【讨论】:

    • “您将收到基于 96 DPI 的系统范围 DPI 缩放/虚拟化的坐标。” -- 或者系统 dpi 设置的任何值。
    • 我认为你是对的,系统根据调用者的 DPI 意识返回值。但是,如果您使用 dpiAware=true,当有多个屏幕时,您将无法获得实际值。在第一种情况下,Windows 仍会缩放非主屏幕以匹配主屏幕。您需要 dpiAware=true/PM。
    猜你喜欢
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    • 2014-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-13
    相关资源
    最近更新 更多