В Windows 8.1 появилась возможность иметь разные настройки DPI для разных мониторов. Эта функция известна как «поддержка высокого разрешения на каждый монитор». Он сохраняется, и был дополнительно доработан в Windows 10.
Если приложение не принимает участия (т.е., не поддерживает DPI или поддерживает высокий DPI), оно будет автоматически увеличено DWM до надлежащего DPI. Большинство приложений попадают в одну из этих двух категорий, включая большинство утилит, поставляемых с Windows (например,, Блокнот). В моей тестовой системе для монитора с высоким DPI установлен масштаб 150% (144 DPI), а для обычного монитора - системный DPI (масштаб 100%, 96 DPI). Поэтому, когда вы открываете одно из этих приложений на экране с высоким разрешением (или перетаскиваете его туда), виртуализация срабатывает, увеличивая все, но также делая его невероятно размытым.
С другой стороны, если приложение явно указывает, что оно поддерживает высокое разрешение для каждого монитора, то виртуализация не выполняется, и разработчик несет ответственность за масштабирование. У Microsoft есть довольно подробное объяснение здесь *, но в качестве самостоятельного вопроса я резюмирую. Во-первых, вы указываете поддержку, задав <dpiAware>True/PM</dpiAware>
в манифесте. Это позволит вам получать WM_DPICHANGED
сообщения, которые сообщают вам как новый параметр DPI, так и предлагаемый новый размер и положение для вашего окна. Он также позволяет вызывать функцию GetDpiForMonitor и получать фактический DPI, без ложных указаний по соображениям совместимости. Кенни Керр также написал подробное руководство.
Я успешно проделал все это в небольшом тестовом приложении на C ++. Здесь много шаблонов и в основном настроек проекта, поэтому я не вижу особого смысла публиковать здесь полный пример. Если вы хотите проверить это, либо следуйте инструкциям Кенни, это руководство в MSDN или загрузите официальный SDK образец. Теперь текст в клиентской области выглядит хорошо (из-за того, что я обработал WM_DPICHANGED
), но поскольку виртуализация больше не выполняется, масштабирование неклиентской области отсутствует. В результате строка заголовка / заголовка и строка меню имеют неправильный размер - они не становятся больше на экране с высоким разрешением:
Итак, вопрос в том, как мне заставить неклиентскую область окна масштабироваться до нового DPI?
Неважно, создаете ли вы свой иметь собственный класс окна или использовать диалог - в этом отношении они ведут себя идентично.
Кроме того, это явно ложь. Настраиваемые строки заголовка не могут быть единственным способом добиться правильного поведения, поскольку команда оболочки Windows сделала это. Скромное диалоговое окно Run ведет себя именно так, как ожидалось, правильно меняя размер как клиентской, так и неклиентской областей, когда вы перетаскиваете его между мониторами с разными DPI:
Исследование с помощью Spy ++ подтверждает, что это просто стандартный диалог Win32 - ничего особенного. Все элементы управления являются стандартными элементами управления Win32 SDK. Это не приложение UWP, и они не отрисовывали строку заголовка на заказ - она по-прежнему имеет стиль WS_CAPTION
. Он запускается процессом explorer.exe, который помечен как поддерживающий высокое разрешение для каждого монитора (проверено с помощью Process Explorer и GetProcessDpiAwareness). Это сообщение в блоге подтверждает что и диалоговое окно «Выполнить», и командная строка были переписаны в Windows 10 для правильного масштабирования (см. «Командные оболочки и др.»). Что делает диалоговое окно "Выполнить" для изменения размера строки заголовка?
Common Item Dialog API, отвечающий за диалоги открытия и сохранения нового стиля, также правильно масштабируется при запуске из процесса, поддерживающего высокое разрешение для каждого монитора, что можно увидеть, нажав кнопку «Обзор» в диалоговом окне «Выполнить». То же самое для API диалогового окна задач, создавая странную ситуацию, когда приложение запускает диалоговое окно с заголовком другого размера < / а>. (Устаревший API MessageBox, однако, не обновлялся и демонстрирует то же поведение, что и мое тестовое приложение.)
Если команда оболочки делает это, это должно быть возможно. Я просто не могу представить, чтобы группа, ответственная за разработку / реализацию поддержки DPI для каждого монитора, не позаботилась о том, чтобы предоставить разработчикам разумный способ создания совместимых приложений. . Подобные функции требуют поддержки разработчика, в противном случае они выходят из строя. Даже приложения WPF не работают - Per-Monitor Aware WPF Sample Проект a> не может масштабировать неклиентскую область, в результате чего строка заголовка имеет неправильный размер. Я не сторонник теорий заговора, но это пахнет маркетинговым ходом, препятствующим разработке настольных приложений. Если это так и официального способа не существует, я приму ответы, основанные на недокументированном поведении.
Говоря о недокументированном поведении, запись сообщений окна, когда диалоговое окно «Выполнить» перетаскивается между мониторами с разными настройками DPI, показывает, что он получает недокументированное сообщение, 0x02E1
. Это несколько интересно, потому что этот идентификатор сообщения ровно на единицу больше задокументированного WM_DPICHANGED
сообщение (0x02E0
). Тем не менее, мое тестовое приложение никогда не получает это сообщение, независимо от настроек распознавания DPI. (Любопытно, что внимательный осмотр действительно показывает, что Windows немного увеличивает размер глифов сворачивания / разворачивания / закрытия в строке заголовка, когда окно перемещается на монитор с высоким разрешением DPI. Они все еще не такие большие как они есть, когда они виртуализированы, но они немного больше, чем глифы, которые он использует для немасштабированных приложений с системным DPI.)
До сих пор моей лучшей идеей было обработать _8 _ сообщение для настройки размера неклиентской области. Используя флаг SWP_FRAMECHANGED
с функцией SetWindowPos
, я может заставить окно изменить размер и перерисовать неклиентскую область в ответ на WM_DPICHANGED
. Это отлично работает, чтобы уменьшить высоту строки заголовка или даже полностью удалить ее, но это никогда не сделает он выше. Заголовок, кажется, достигает максимума на высоте, определяемой системным DPI. Даже если бы это сработало, это не было бы идеальным решением, потому что это не помогло бы с системной строкой меню или полосами прокрутки, но, по крайней мере, это было бы началом. Другие идеи?
* Я знаю, что в этой статье говорится: " Обратите внимание, что неклиентская область приложения, поддерживающего разрешение каждого монитора, не масштабируется Windows и будет казаться пропорционально меньше на дисплее с высоким разрешением. " a> См. выше, почему это (1) неправильно и (2) неудовлетворительно. Я ищу обходной путь, кроме настраиваемого рисования неклиентской области.
WM_DPICHANGED
DefWindowProc
? - person Jonathan Potter   schedule 24.05.2016DefWindowProc
(кромеWM_PAINT
), так что это позаботится даже о недокументированных сообщениях. - person Cody Gray   schedule 24.05.2016WS_CAPTION
. Я предполагаю, что он мог использоватьWM_NCCALCSIZE
для удаления строки заголовка, нарисованной системой, и рисования своей собственной. Да, я пробовал все это, скачав последнюю версию набора инструментов Visual Studio. Определенно установлено на v140 и, в частности, нацелено на последнюю версию Windows 10 (10586). - person Cody Gray   schedule 26.05.2016