Приложение масштабируется дважды на мониторе с высоким разрешением - PullRequest
0 голосов
/ 05 июля 2019

Я разрабатываю приложение winapi с поддержкой dpi и столкнулся с проблемой, что его окно масштабируется дважды без какой-либо причины.Похоже, что масштабирование точек на дюйм применяется дважды после создания окна приложения.Вот мой кодСначала я делаю свое приложение с поддержкой dpi:

::SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);

Затем я рассчитываю шкалу dpi моего монитора и создаю окно 500 на 500 с учетом этой шкалы:

dpiScale = <get dpi scale using ::GetDpiForMonitor()> / 96.f;
hWnd = ::CreateWindow(..., 0, 0, 500 * dpiScale, 500 * dpiScale, ...);

Я также хочу, чтобы мойминимальный размер окна 500 на 500:

case WM_GETMINMAXINFO:
{
    MINMAXINFO* info = (MINMAXINFO*)lParam;
    info->ptMinTrackSize.x = 500 * dpiScale;
    info->ptMinTrackSize.y = 500 * dpiScale;
    break;
}

Затем я реализую обработку событий, измененную в dpi:

case WM_DPICHANGED:
{
    dpiScale = LOWORD(wParam) / 96.f;
    RECT rect = *(RECT *)lParam;
    ::SetWindowPos(... rect ...);
    break;
}

Когда я запускаю свое приложение на мониторе с высоким dpi, например 120 (масштабный коэффициент х1.25) окно приложения выглядит больше, чем должно быть.Я также попытался распечатать размер окна для каждого WM_SIZE сообщения:

case WM_SIZE:
{
    RECT r;
    ::GetWindowRect(hWnd, &r);
    int width = (r.right - r.left);
    int height = (r.bottom - r.top);
    std::cout << "WM_SIZE " << width << " " << height << " scale factor: " << (width / 500.f) << std::endl;
    break;
}

и вот что я получаю:

WM_SIZE 625 625 scale factor: 1.25
WM_SIZE 781 781 scale factor: 1.562

Обратите внимание, что есть только два места, где я применяю масштабирование dpiвручную - создание окон и обработка сообщений WM_GETMINMAXINFO.Я также попытался удалить масштабирование dpi из вызова ::CreateWindow(), и это ничего не изменило.

Похоже, что Windows автоматически изменяет размер моего окна, хотя я установил осведомленность о dpi для своего приложения.Почему это происходит?Как я могу обойти это?Спасибо.

ОБНОВЛЕНО:

Я создал минимальный воспроизводимый пример, который можно найти здесь: https://gist.github.com/APodlinny/179b90b9e0d45ea9576d33dca2273dce Вы можете использовать файлы проекта MSVC.из gist или создайте пустой проект Win32 MSVC, добавьте исходный файл main.cpp и убедитесь, что: * используется Windows SDK 8.1 или новее (проверьте каталоги VC в настройках проекта, а именно каталоги include и library) * shcore.lib библиотека находится вДополнительные зависимости компоновщика * Подсистема компоновщика Console

Может быть, в Windows 10 включено масштабирование с высоким разрешением для приложения?

Я сомневаюсь, что это потому, что я явно установил осведомленность о dpiдля моего приложения в начале функции _tWinMain(...).Параметр «Переопределить масштабирование точек на дюйм» в настройках совместимости приложения также не отмечен.Кроме того, само содержимое окна также не масштабируется.

Есть ли разница в масштабировании между основным монитором и тем, на котором работает ваше приложение?

Да, но я не думаю, что это имеет значение.У меня есть два монитора, и я протестировал свое приложение в двух конфигурациях: 1. Вторичный 125%, первичный 100%, окно создано на вторичном мониторе.2. Вторичный 125%, первичный 125%, окно создано на основном мониторе.В обоих случаях окно масштабируется дважды.

Ошибка в другом коде.Установите точку останова на ::GetWindowRect(hWnd, &r); в обработчике WM_SIZE.Запустите отладчик, когда он остановится на точке останова, и снова запустите его.Когда он останавливается во второй раз, проверьте стек вызовов, чтобы найти источник второго WM_SIZE.

Спасибо за подсказку!Оказалось, что второе сообщение WM_SIZE вызвано сообщением WM_WINDOWPOSCHANGED, отправленным Windows:

case WM_WINDOWPOSCHANGED:
{
    WINDOWPOS* pos = (WINDOWPOS*)lParam;
    std::cout << "WM_WINDOWPOSCHANGED " << pos->x << " " << pos->y << " " << pos->cx << " " << pos->cy << std::endl;
    return DefWindowProc(hWnd, message, wParam, lParam);
}
WM_WINDOWPOSCHANGED 100 100 625 625
WM_SIZE 625 625 scale factor: 1.25
WM_WINDOWPOSCHANGED 100 100 781 781
WM_SIZE 781 781 scale factor: 1.562

Первая пара WM_WINDOWPOSCHANGED / WM_SIZE вызвана ::ShowWindow()вызов, второй можно отследить до ::GetMessage(), но я не знаю, что вызывает отправку этих сообщений.

...