我正在开发一个在 Windows 10 和 8.1 上运行的应用程序,并且在具有不同 DPI 的显示器之间移动时遇到了缩放非工作区(菜单栏、标题栏)的问题。处理了工作区,但非工作区不成比例。DPI 感知设置为 PerMonitorAware(v1,因为 v2 在 Windows 8.1 上不可用)。
EnableNonClientDpiScaling 函数完全符合我的需求(它是所有类似问题的公认答案) - 唉,它只是 Windows 10 开始的 API 的一部分。
有没有办法在没有前面提到的功能的情况下手动处理这个问题 - 为了保持对 Windows 8.1 的支持?或者,支持 Windows 8.1 是否意味着在使用不同 DPI 的屏幕之间移动时无法调整非工作区的大小?
DPI 支持是一个移动目标,您只需要确定支持的最低平台是什么,并接受多显示器扩展在这些旧平台上并不完美。
在可用的版本上调用EnableNonClientDpiScaling
(GetProcAddress
或您使用的任何语言的等效版本)。
新的感知清单元素在 Windows 10 中的工作方式意味着,你可以在支持它的地方使用每监视器 v2(1703 及更高版本),在旧版本中可以是 PMv1、系统或无感知。PMv2 可让您自动缩放基于DialogBox
的对话框。
感谢安德斯,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.");
}