winapi - WM_DPICHANGED 在循环中调用,大小未从 WM_GETDPISCALEDSIZE 返回
问题描述
我试图让我们的 WinAPI 应用程序支持 DPI,并遇到了一个明显的无限循环,其中窗口不断接收 WM_DPICHANGED。如文档所述,该程序始终使用 WM_DPICHANGED 消息的 lParam 调用 SetWindowPos。
我的显示器设置在右侧有显示器 1,1920x1080,100% 缩放,左侧有显示器 2,在底部对齐,3840x2160,150% 缩放。运行以下程序,移动窗口,使其横跨两个显示器,但缩放为 100%。现在,抓住左侧显示器上的窗口,垂直上下移动窗口,使其在两种分辨率之间切换。在某些时候,它进入一个似乎停止整个窗口管理器的循环(ctrl-alt-del 会中断它——不需要实际终止程序)。
在这个循环中,传入 lParam 的矩形的大小为 500x500,用于 96 和 144 DPI!为什么 WM_DPICHANGED 得到一个大小不是从 WM_GETDPISCALEDSIZE 返回的矩形?
我知道我在做一些不寻常的事情,让窗口在更高 DPI 显示器上变小(在真实的应用程序中,我们的窗口具有复杂的布局,这些布局会根据分辨率而变化)。
为什么会出现这种循环,我们如何避免 DPI 更改循环?
#include "stdafx.h"
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_GETDPISCALEDSIZE:
{
LPSIZE lpSize = (LPSIZE)lParam;
int dpi = wParam;
lpSize->cy = lpSize->cx = (dpi == 96 ? 200 : 500);
return TRUE;
}
case WM_DPICHANGED:
{
LPRECT lpRect = (LPRECT)lParam;
SetWindowPos(hWnd, nullptr, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
WCHAR szTitle[] = L"Test"; // The title bar text
WCHAR szWindowClass[] = L"TESTCLASS"; // the main window class name
ATOM MyRegisterClass(HINSTANCE);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
MyRegisterClass(hInstance);
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_VISIBLE,
200, 200, 200, 200, nullptr, nullptr, hInstance, nullptr);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = nullptr;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = nullptr;
return RegisterClassExW(&wcex);
}
解决方案
wParam
似乎可以通过检测 DPI 中的 DPI 是否与返回的匹配来解决这种情况GetDpiForWindow
,并在这种情况下忽略WM_DPICHANGED
。
推荐阅读
- office-ui-fabric - 同一行办公室 ui 织物中的 2 个元素
- python - The Foundry Nuke – 获取字体文件路径
- javascript - 创建链接打开时在后台运行的隐藏 HTML 页面
- android - 每次单击主页按钮时,如何让android后退按钮关闭应用程序?
- mysql - 如何从 express-openapi mysql.query() 调用中获取 JSON 输出?
- javascript - 在Javascript / AJAX中为数组中的多个值运行函数
- android - Moshi 解析具有重复字段的嵌套对象
- google-chrome - 无法调整在 Chrome 无头上运行 TestCafe 的窗口大小
- javascript - VueJS 访问嵌套组件数据值
- python - 你如何在 python 上为基于文本的 rpg 循环?