Проблемы с приложением MFC MDI с поддержкой DPI для каждого монитора

Я работаю над тем, чтобы приложение MFC правильно отображалось в средах с несколькими мониторами с разным масштабированием DPI. Есть одна проблема, которую я не могу объяснить, которая возникает, когда основной и дополнительный мониторы работают с разными DPI, а приложение находится на дополнительном мониторе.

Если основной монитор имеет масштабирование 100% DPI (96), а дополнительный монитор имеет такое же масштабирование 100% DPI, все в порядке.

Если основной монитор имеет масштабирование 100% DPI (96), а дополнительный монитор имеет масштабирование 125% (120 DPI) или масштабирование 150% (144 DPI) или любое другое более высокое значение, когда дочерние окна развернуты, часть дочерней оконной системы полоса видна, как показано здесь:

Масштабирование 125%: введите здесь описание изображения

Масштабирование 150%: введите здесь описание изображения

Если присмотреться, то 7 пикселей для 125% и 14 для 150%. Учитывая, что системная полоса составляет 29 пикселей при масштабировании 100 %, 36 и 125 % и 43 пикселя при масштабировании 150 %, эти 7 и 14 пикселей представляют собой разницу в высоте между размером полосы при масштабе 125 % и 150 % соответственно по сравнению со 100 % базовый уровень.

Таким образом, создается впечатление, что положение и размер полосы вычисляются системой при запуске на основном мониторе.

Когда вы разворачиваете дочернее окно, окну отправляется серия сообщений Windows: WM_GETMINMAXINFOWM_WINDOWPOSCHANGINGWM_GETMINMAXINFOWM_NCCALSIZEWM_WINDOWSPOSCHANGEDWM_MOVEWM_SIZE. WM_GETMINMAXINFO отправляется, когда размер или положение окна вот-вот изменится, чтобы приложение могло переопределить, например, максимальный размер и положение окна по умолчанию. По этому поводу есть примечание:

Для систем с несколькими мониторами элементы ptMaxSize и ptMaxPosition описывают максимальный размер и положение окна на основном мониторе, даже если окно в конечном итоге разворачивается на дополнительный монитор. В этом случае оконный менеджер корректирует эти значения, чтобы компенсировать разницу между основным монитором и монитором, на котором отображается окно. Таким образом, если пользователь оставляет ptMaxSize нетронутым, окно на мониторе, большем, чем основной монитор, максимизируется до размера большего монитора.

Существует статья Рэймонда Чана, объясняющая это: Как настраивается оконный менеджер ptMaxSize и ptMaxPosition для нескольких мониторов?.

Таким образом, ptMaxSize должен быть заполнен размерами основного монитора. Мой основной монитор 2560x1440 пикселей, а размер дополнительного монитора 1920x1200. Однако значение размера, которое я получаю здесь, составляет 1757x1023 и 1761x1027 (при последовательных вызовах). Это не размер основного или дополнительного монитора.

Я попытался сделать грязный трюк и обработал сообщение WM_NCCALCSIZE и установил позицию (слева, сверху) на 0 (относительно родителя).

void CMyMDIChildWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
   CMDIChildWnd::OnNcCalcSize(bCalcValidRects, lpncsp);   
   if (condition)
   {
      lpncsp->rgrc[0].left = 0;
      lpncsp->rgrc[0].top = 0;
   }
}

Работает нормально, пока дочернее окно имеет фокус. Если я нажимаю на другое окно, и оно теряет фокус, полоса перерисовывается и отображается в предыдущей позиции. Этот трюк говорит только о том, где начинается клиентская область, поэтому, когда неклиентская область перерисовывается, я возвращаюсь к исходной проблеме.

Мой вопрос в том, что может быть корнем этой проблемы и как я могу попытаться это исправить?


person Marius Bancila    schedule 28.04.2021    source источник
comment
Существует множество способов программирования приложений MFC. Я не воспроизвожу никаких проблем со стандартным шаблоном MFC с настройкой Per Monitor High DPI Aware или без нее и двумя разными мониторами. Но ваша синяя лента с двумя значками выглядит нестандартно. У вас есть воспроизводимый код/проект?   -  person Simon Mourier    schedule 28.04.2021
comment
Нет, у меня нет воспроизводимого кода. Я сделал приложение MDI MFC, и максимизация дочерних окон работает нормально. Пользовательский интерфейс моего приложения полностью настроен. Но это не так уж особенно. Синяя полоса — это строка меню, а под ней — панели инструментов. Я не делал скриншот всего окна, только соответствующую часть.   -  person Marius Bancila    schedule 28.04.2021
comment
Мне жаль, что я не могу собрать проект, чтобы воспроизвести вашу проблему, поэтому я все же надеюсь, что вы сможете предоставить воспроизводимый образец. Возможно, вы можете обратиться к этому возможно связанная тема.   -  person Song Zhu    schedule 29.04.2021
comment
Я предполагаю, что у вас возникли проблемы с обработкой неклиентской области для основной формы.   -  person Daniel Sęk    schedule 29.04.2021
comment
На самом деле, основной фрейм не обрабатывает ни сообщение WM_NCPAINT, ни другое неклиентское сообщение (ни WM_PAINT, ни WM_ERASEBKGND в этом отношении). Там не так много всего происходит.   -  person Marius Bancila    schedule 29.04.2021
comment
Вы должны вложить в него больше работы. Попробуйте воспроизвести это поведение в стандартном приложении MDI, созданном мастером MFC, сравните координаты с помощью Spy++. Например, высота верхней рамки окна (заголовок и размер) на моем компьютере (Windows 10, 96DPI) составляет 31 пиксель (вы используете 29). К сожалению, мы не можем вам помочь, потому что кажется, что приложения, созданные мастером MFC, не имеют этой проблемы.   -  person Daniel Sęk    schedule 29.04.2021