如何在DPI识别的获胜应用程序上缩放标题栏?

时间:2015-08-03 07:34:48

标签: c++ winapi windows-8.1 dpi windows-10

我通过在清单文件中设置<dpiAware>True/PM</dpiAware>,使每个监视器的应用程序dpi感知。我可以使用进程资源管理器验证这确实有效,或者通过调用GetProcessDpiAwareness来验证。

这一切都运行正常,我可以在我的代码中很好地扩展客户端区域中的任何内容。但是,我唯一的问题是,如果我将我的应用程序从system-dpi监视器拖到非系统dpi监视器,标题栏和任何系统菜单将变得太大或太小。对于大多数内置应用程序(例如计算,边缘浏览器等),情况并非如此,因此必须要妥善扩展它。 MS的开发人员有没有这样做过?

下面的截图可以更好地解释我的问题。另请注意,关闭,最小和最大按钮之间的填充在缩放(96dpi)时是不同的。

Screenshot

Sample app我附加了一个非常简单的应用程序,每个监视器都支持dpi。

4 个答案:

答案 0 :(得分:10)

Windows 10周年更新(v1607)添加了一个新API,您必须调用该API才能启用非客户区域的DPI扩展:EnableNonClientDpiScaling。收到WM_NCCREATE时,应调用此函数。在窗口创建期间,消息被发送到窗口的过程回调。

示例:

case WM_NCCREATE:
{
    if (!EnableNonClientDpiScaling(hWnd))
    {
        // Error handling
        return FALSE;
    }

    return DefWindowProcW(...);
}

如果应用程序的DPI感知上下文为DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,则应省略调用EnableNonClientDpiScaling,因为它不会产生任何影响,尽管该函数仍将成功返回。

来自the documentation

  

默认情况下,未启用顶级窗口的非客户端扩展。您必须调用此API,以便为您希望自动为非客户区域扩展的每个顶级窗口启用它。一旦你这样做,就无法禁用它。启用非客户端扩展意味着系统为窗口绘制的所有区域将自动缩放以响应窗口上的DPI更改。其中包括标题栏,滚动条和菜单栏等区域。如果希望操作系统负责根据监视器的API自动以正确的大小渲染这些区域,则需要调用EnableNonClientDpiScaling

有关Windows 10 AU中DPI扩展更改的其他信息,请参阅this blog post

答案 1 :(得分:7)

  

MS的开发人员是怎么做到的?

这是一个非常令人失望的答案。使用Alin Constantin的WinCheat并检查Calculator的顶级窗口,我看到窗口大小为320x576,客户端大小也是320x576。

换句话说,微软完全通过抑制窗口的非客户区域来避免这个问题,而是将所有内容放在客户区域中。为您做好这项工作可能涉及自定义绘制标题栏。

值得注意的是计算器和Windows资源管理器不对标题栏使用相同的颜色。做标题栏自定义绘图的计算器可以很好地解释这一点。

答案 2 :(得分:0)

documentation说:

  

请注意,每个monitor-DPI感知应用程序的非客户端区域不会被Windows缩放,并且在高DPI显示器上会按比例缩小。

您链接的Microsoft应用程序通过删除非客户区域并使客户区覆盖整个窗口来处理此问题。

答案 3 :(得分:0)

<强>更新

向manifest表示添加新的<dpiAwarness>声明以解决所有这些混乱就足够了。示例是here

以前调查的遗留物(已废弃):

关于这个问题的更多调查。

系统设置:两个显示器,一个是96 dpi,另一个是267 dpi(Microsoft Surface 4)。

测试窗口移动到辅助96 dpi监视器:

以下是清单中的<dpiAware>true/pm</dpiAware>渲染(错误,IMO):

enter image description here

请注意标题栏的大小和窗口图标的大小错误。

使用<dpiAware>true</dpiAware>

进行正确渲染

enter image description here

我怀疑MSDN文档明显误导了PROCESS_DPI_AWARENESS的值。我发现<dpiAware>true</dpiAware><dpiAware>true/pm</dpiAware>之间的消息和样式没有任何差异。后者只是使标题更大。在这两种情况下,应用程序在具有不同DPI的监视器之间移动时接收WM_DPICHANGED消息。

叹息。