Я пытаюсь сделать наше приложение WinAPI зависимым от DPI и столкнулся с очевидно бесконечным циклом, в котором окно постоянно получает WM_DPICHANGED. Программа всегда вызывает SetWindowPos с lParam сообщения WM_DPICHANGED, как сказано в документации.
Моя конфигурация монитора имеет монитор 1 справа, 1920x1080, масштабирование 100%, и монитор 2 слева, выровненный снизу, 3840x2160, масштабирование 150%. Запустив следующую программу, переместите окно так, чтобы оно располагалось между двумя мониторами, но при 100% масштабировании. Теперь возьмите окно на левом мониторе и переместите окно вверх и вниз по вертикали, чтобы оно переключалось между двумя разрешениями. В какой-то момент он входит в цикл, который, кажется, останавливает работу всего оконного менеджера (ctrl-alt-del прервет его - нет необходимости фактически завершать программу).
В этом цикле прямоугольник, переданный в lParam, имеет размер 500x500 для 96 и 144 точек на дюйм! Почему WM_DPICHANGED получает прямоугольник, размер которого отличается от размера, возвращенного из WM_GETDPISCALEDSIZE?
Я знаю, что делаю что-то необычное, уменьшая размер окна на мониторе с более высоким разрешением (в реальном приложении наши окна имеют сложные макеты, которые меняются в зависимости от разрешения).
Почему возникает этот цикл и как избежать цикла изменения 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);
}
MonitorFromWindow
- записать результат в консоль или файл. - person Daniel Sęk   schedule 05.09.2018