扩展非客户端区域,以在支持Windows 8.1的应用程序上实现每个监视器的高DPI支持

时间:2019-01-09 12:34:48

标签: winapi windows-8.1 dpi highdpi

我正在开发一个在Windows 10和8.1上运行的应用程序,该应用程序遇到了在具有不同DPI的显示器之间移动时缩放非客户区域(菜单栏,标题栏)的问题。客户区已处理,但非客户区超出比例。 DPI意识设置为PerMonitorAware(由于Windows 8.1上不支持v2,因此为v1)。

EnableNonClientDpiScaling函数完全满足我的需要(这是所有类似问题的公认答案)-it,它只是Windows 10上API的一部分。

是否有一种方法可以手动处理此问题而无需前面提到的功能-为了保持对Windows 8.1的支持?还是支持Windows 8.1意味着在具有不同DPI的屏幕之间移动时无法调整非工作区的大小?

2 个答案:

答案 0 :(得分:3)

DPI支持是一个不断发展的目标,您只需确定最低支持的平台是什么,并接受多显示器缩放在这些旧平台上并不是完美的选择。

在可用的版本(EnableNonClientDpiScaling或使用您使用的任何语言的等效语言)上致电GetProcAddress

新的感知清单元素在Windows 10中的工作方式意味着您可以是受支持的Per-Monitor v2(1703和更高版本),以及在较早版本上支持PMv1,System或Unaware。 PMv2使您可以自动缩放基于DialogBox的对话框。

答案 1 :(得分:1)

多亏了安德斯(Anders),GetProcAddress才是我一直在寻找的东西。尽管它不能解决在Win 8.1上调整非客户区域大小的问题(似乎除了自己绘制所有内容外别无其他方法),但它可以在Win 10上设置最新的DPI_AWARENESS_CONTEXT

// the following sets PROCESS_PER_MONITOR_AWARE_V2 on Win10 and
// reverts to PROCESS_PER_MONITOR_AWARE on Win 8.1

typedef BOOL(__stdcall *SetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
SetProcessDpiAwarenessContext dpi_call = nullptr;
dpi_call = reinterpret_cast<SetProcessDpiAwarenessContext>(GetProcAddress(
    GetModuleHandle(TEXT("User32.dll")),
    "SetProcessDpiAwarenessContext"));
if (dpi_call != nullptr) {
    if (!(*dpi_call)((DPI_AWARENESS_CONTEXT) - 4))
        throw std::runtime_error("Unable to set DPI aware app.");
} else {
    if (SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) != S_OK)
        throw std::runtime_error("Unable to set DPI aware app.");
}