Масштабирование области без клиента (строка заголовка, строка меню) для поддержки высокого разрешения для каждого монитора

В Windows 8.1 появилась возможность иметь разные настройки DPI для разных мониторов. Эта функция известна как «поддержка высокого разрешения для каждого монитора». Это сохраняется ибыл доработан в Windows 10.

Если приложение не принимает (то есть(либо не поддерживает DPI, либо поддерживает высокое разрешение), он будет автоматически увеличен с помощью DWM до нужного значения DPI. Большинство приложений попадают в одну из этих двух категорий, включая большинство утилит в комплекте с Windows (напримерБлокнот). В моей тестовой системе монитор с высоким DPI настроен на шкалу 150% (144 DPI), в то время как обычный монитор настроен на системный DPI (100% шкала, 96 DPI). Поэтому, когда вы открываете одно из этих приложений на экране с высоким разрешением (или перетаскиваете его туда), виртуализация включается, увеличивая все, но также делая его невероятно размытым.

С другой стороны, если приложение явно указывает, что оно поддерживает монитор с высоким DPI, то виртуализация не выполняется и разработчик отвечает за масштабирование. У Microsoft есть довольно полное объяснениеВот*Но для пользы отдельного вопроса я подведу итоги. Во-первых, вы указываете поддержку, установив<dpiAware>True/PM</dpiAware> в манифесте. Это позволяет вам получатьWM_DPICHANGED Сообщения, который говорит вам как о новой настройке DPI, так и о предлагаемом новом размере и позиции для вашего окна. Это также позволяет вам позвонитьGetDpiForMonitor функционировать и получитьфактический DPI, без лжи по причинам совместимости. Кенни Керр также написалвсеобъемлющий учебник.

Я получил все это успешно в небольшом тестовом приложении C ++. Это много шаблонных и в основном настроек проекта, поэтому я не вижу особого смысла публиковать здесь полный пример. Если вы хотите проверить это, либо следуйте инструкциям Кенни,этот учебник на MSDNили скачатьофициальный образец SDK, Теперь текст в клиентской области выглядит хорошо (из-за моей обработкиWM_DPICHANGED), но поскольку виртуализация больше не выполняется, отсутствует масштабирование не клиентской области. В результате строка заголовка / заголовка и строка меню являютсяне тот размер- они не становятся больше на экране с высоким DPI:

Итак, вопрос в том, как мне получитьне клиентская зона окна масштабировать до нового DPI?
Неважно, создаете ли вы свой собственный класс окна или используете диалог - они ведут себя одинаково в этом отношении.

Этобыло предложено что тамявляется нет ответа - ваш единственный выбор - нарисовать все окно, включая не клиентскую область. Хотя это, безусловно, возможно, и в действительности то, что делают приложения UWP (ранее известные как Metro), такие как калькулятор Windows 10, это нереальный вариант для настольных приложений, которые используют множество не клиентских виджетов и надеются выглядеть нативно.

Помимо этого, это явно ложно. Пользовательские нарисованные заголовкине могу быть единственным способом получить правильное поведение, так как команда оболочки Windows сделала это. Скромное диалоговое окно «Выполнить» ведет себя точно так же, как и ожидалось, правильно изменяя размеры как клиентских, так и не клиентских областей при перетаскивании его между мониторами с разными DPI:

Расследование со Spy ++ подтверждает, что это просто стандартное диалоговое окно Win32 - ничего особенного. Все элементы управления являются стандартными элементами управления Win32 SDK. Это не приложение UWP, и они не нарисовали строку заголовка - оно все еще имеетWS_CAPTION стиль. Он запускается процессом explorer.exe, которыйявляется помечается как поддержка высокого разрешения для каждого монитора (проверено с помощью Process Explorer и GetProcessDpiAwareness).Этот пост в блоге подтверждает, что как диалоговое окно «Выполнить», так и командная строка были переписаны в Windows 10 для правильного масштабирования (см. «Командные снаряды и др.«).Что делает диалог «Выполнить», чтобы изменить размер строки заголовка?

Common Item Dialog APIОтвечает за диалоги открытия и сохранения в новом стиле, а также корректно масштабируется при запуске из процесса с поддержкой высокого разрешения для каждого монитора, что можно увидеть, нажав кнопку «Обзор» в диалоговом окне «Выполнить». То же самое дляAPI диалога задач, создаваястранная ситуация, когда приложение запускает диалоговое окно с строкой заголовка другого размера, (Однако устаревший API MessageBox не обновлялся и демонстрирует то же поведение, что и мое тестовое приложение.)

Если команда оболочки делает это, это должно быть возможно. Я просто не могу себе представить, что команда, ответственная за разработку / реализацию поддержки DPI для каждого монитора, пренебрегла разработчиками разумным способом создания совместимых приложений. Такие функции, как эта, требуют поддержки разработчика, или они не готовы к работе. Даже приложения WPF не работают - MicrosoftПример WPF для каждого монитора Проект не может масштабировать не-клиентскую область, что приводит к неправильному размеру строки заголовка. Я не очень за теории заговора, но это пахнет маркетинговым ходом, чтобы препятствовать разработке настольных приложений. Если так, и официального пути нет, я приму ответы, которые основаны на недокументированном поведении.

Говоря о недокументированном поведении, запись сообщений окна при перетаскивании диалогового окна «Выполнить» между мониторами с различными настройками DPI показывает, что он получает недокументированное сообщение,0x02E1, Это несколько интересно, потому что этот идентификатор сообщения ровно на один больше, чем документированныйWM_DPICHANGED сообщение (0x02E0). Мое тестовое приложение никогда не получает это сообщение, независимо от его настроек DPI-осведомленности. (Любопытно, что тщательная проверка показывает, что Windowsнемного увеличивает размер символов минимизации / максимизации / закрытия в строке заголовка при перемещении окна на монитор с высоким разрешением. Они по-прежнему не такие большие, как в виртуализированном виде, но они немного больше глифов, которые он использует для немасштабированных приложений с системным DPI.)

До сих пор моей лучшей идеей было справиться сWM_NCCALCSIZE сообщение для настройки размера не клиентской области. ИспользуяSWP_FRAMECHANGED флаг сSetWindowPos функцияЯ могу заставить окно изменить размер и перерисовать свою не клиентскую область в ответ наWM_DPICHANGED. Это прекрасно работает, чтобы уменьшить высоту строки заголовка или даже полностью удалить ее, но никогда не сделает ее выше, Заголовок, кажется, достигает максимума на высоте, определенной системным DPI. Даже если бы это работало, это не было бы идеальным решением, потому что это не помогло бы с нарисованной системой строкой меню или полосами прокрутки… но по крайней мере это было бы началом. Другие идеи?

* Я знаю, что эта статья говорит«Обратите внимание, что область, не относящаяся к клиенту, для каждого приложения, поддерживающего монитор / DPI, не масштабируется Windows и будет отображаться пропорционально меньше на дисплее с высоким DPI». Смотрите выше, почему t, шляпа (1) неверна и (2) неудовлетворительна. Я ищу обходной путь, отличный от нестандартного рисования не клиентской области.

Ответы на вопрос(2)

Ваш ответ на вопрос