Windows приложения, размер которых изменен с помощью Win32.MoveWindow при отладке, неправильно масштабируются на 125% - PullRequest
0 голосов
/ 05 апреля 2020

Я использую мониторы 2560x1440 с масштабом от Windows 10 до 125%. Я написал C# пример модульного теста в Visual Studio 2019, который вызывает DLL для 1), находит дескрипторы окон различных приложений (блокнот, WordPad, и т. Д. c) и 2) изменяет их размер до уровня чуть менее 100% монитора. размер. Я использовал Win32.MoveWindow для перемещения, вот так:

//    MoveWindow(hWnd, left, top, width, height)
Win32.MoveWindow(hWnd, 0, 0, 2500, 1400, true);

Проблема в том, что при отладке в модульном тесте Windows10 масштабирует 2500 и 1400 пикселей на 125% и перемещает windows к этому большему размеру. Затем windows свисают с нижнего и правого краев экрана.

В отличие от этого, когда я запускаю один и тот же код DLL из скелета Windows Forms app (и без отладки), код работает отлично, Windows изменяет размеры приложения Notepad и Wordpad windows правильно.

Я передаю одинаковые номера Win32.MoveWindow в обоих случаях.

В случае, если это имеет значение, для кода DLL я пробовал бесконечные комбинации app.config и app.manifest настройки для моего кода DLL, который вызывает Win32.MoveWindow (и я нацеливаюсь NET 4.7.2), но безуспешно.

Для скелетного приложения Forms я попробовал 4.6.1 и 4.7.2 без настроек DPI в app.config и с включенным параметром «dpiAware = true» в app.manifest. (Конечно, ни скелетное приложение Forms, ни DLL не поддерживают DPI. Я только что попробовал включить и выключить настройку.)

Единственная вещь, которая, кажется, имеет значение - это отладка. Я ожидал, что смогу использовать обычные пиксели экрана от границ экрана ОС, когда выполняю операции MoveWindow, но это не очень хорошо работает при отладке.

Как правильно изменить размеры других приложений с помощью Win32.MoveWindow ? Должно ли мое приложение определить текущий коэффициент масштабирования, а затем уменьшить число, которое я передаю Win32.MoveWindow? (Я бы передал 2500 / 1.25 = 2000 к Win32.MoveWindow, например, для масштабирования 125%.)

Предполагается ли отладчик вмешиваться в масштабирование и масштабирование, как это? Это известная проблема?

1 Ответ

0 голосов
/ 07 апреля 2020

@ selb ie было полностью правильно и точно в цель с его комментарием. Он даже был достаточно любезен, чтобы выделить одну из ключевых фраз, чтобы я обратил на это внимание. @ selb ie облегчил мне задачу. Ниже я включил фрагменты моего тестового кода.

Windows Поведение

Как указывал @ selb ie, если в настройках специальных возможностей включено масштабирование 125%, чтобы сделать все больше, Windows сообщает о разном размере экрана для осведомленных и незнакомых процессов.

Для процессов, поддерживающих DPI, Windows сообщит 2560x1440, потому что они должны уменьшить свое мышление, чтобы Windows мог увеличить его на 125% для получения четкого текста и т. Д. c.

Для процессов, не поддерживающих DPI, Windows сообщит вызывающему абоненту 2048x1152, чтобы вызывающий считал, что экран меньше, чем он есть на самом деле. Windows увеличивает количество заказов вызывающего абонента на 125%, чтобы размеры абонента соответствовали аппаратному размеру экрана (2560x1440).

Проблема

Проблема, с которой я столкнулся, заключалась в том, что мой код модульного теста ( DPI unaware) использовал размеры аппаратного обеспечения в моем коде DLL (2560x1440), полученном из базы данных, а не ОС, поэтому, когда Windows увеличил его, мои перемещенные windows были больше, чем размер аппаратного экрана.

Когда одна и та же DLL использовалась в приложении Forms с поддержкой DPI, Windows разрешалось для всего (без увеличения net), а перемещенный windows соответствовал аппаратным экранам.

Решения

Первое решение состоит в том, чтобы ваш процесс вызова учитывал DPI, чтобы вы могли использовать аппаратные размеры экрана в своем коде. Сделайте это, вызвав Win32 API в NET 4.6 и выше. Это то, что я использовал в своем модульном тесте для правильной работы.

[STAThread]
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();

static void Main() {
    if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
    ... either ConsoleApp code or Windows.Forms code here
}

Второе решение - включить поддержку DPI в файле EXE app.manifest. Просто раскомментируйте код XML по умолчанию в файле app.manifest по умолчанию, созданном AddNew в Visual Studio.

APP.MANIFEST FILE
<application xmlns = "urn:schemas-microsoft-com:asm.v3" >
  <windowsSettings >
  <dpiAware xmlns = "http://schemas.microsoft.com/SMI/2005/WindowsSettings" >
      true </dpiAware >
  </windowsSettings >
</application >

В NET 4.7 и выше, вы также можете использовать новые настройки PerMonitorV2 DPI в файле app.config, а не в файле app.manifest. Это, по-видимому, позволяет использовать разную чувствительность к DPI для разных мониторов. (Я еще не пробовал это, но я упоминаю здесь для полноты.)

<configuration>
    <!--requires NET 4.7, and the default is false />
    <System.Windows.Forms.ApplicationConfigurationSection>
        <add key="DpiAwareness" value="PerMonitorV2" />
        <add key="EnableWindowsFormsHighDpiAutoResizing" value="false" />
    </System.Windows.Forms.ApplicationConfigurationSection>
</configuration>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...