SetWindowPos () кросс-процесс с несколькими мониторами и различными масштабами отображения - PullRequest
0 голосов
/ 18 февраля 2019

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

Яиспользуя SetWindowPos() для перемещения / изменения размера окон из другого процесса.Это прекрасно работает до тех пор, пока все экраны используют одинаковое масштабирование экрана, но в следующем сценарии он не работает должным образом:

  • Основной экран имеет значение (0,0) с 3440x1440 иМасштабирование 150%.
  • Вторичный экран имеет значение (3440, 0) с масштабированием 900x1440 и 100%.
  • Мое приложение - PROCESS_PER_MONITOR_DPI_AWARE_V2, а целевое приложение - PROCESS_DPI_UNAWARE (масштабируется с помощьюWindows).

Теперь, если я переместлю окно так, чтобы верхний левый угол находился на основном экране, а центр все еще оставался на дополнительном экране, например (3400, 0).

  SetWindowPos(hwnd, HWND_BOTTOM, 3300, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);

Затем происходит следующее:

  • Окно масштабируется в соответствии со 100% масштабированием экрана второго экрана.
  • Окно не перемещено в (3300,0).Вместо этого координаты, которые он получает в сообщении WM_WINDOWPOSCHANGING, равны (2200, 0).Кажется, координаты уменьшены до логических координат.

Поэтому я не могу переместить окно в это место.Я пытался использовать PhysicalToLogicalPointForPerMonitorDPI() в координатах, которые я передаю SetWindowPos(), но безуспешно (он даже не меняет координаты).

Теперь кажется, что я просто не могу переместить окно в какое-либо положение, так что верхний левый угол находится на основном экране, но центр окна все еще находится на дополнительном экране, потому что Windows уменьшит координатыи если я увеличу их вручную, то я бы уже разместил окно на втором экране, и Windows больше не применяет масштабирование.Даже если бы мне удалось обойти это, ручной расчет масштабирования возможен с помощью двухэкранной настройки, но быстро становится слишком сложным с большим количеством экранов.Итак, как мне заставить это работать?

EDIT1: Я пытался использовать SetThreadDpiAwarenessContext() как предложено, но это все еще не работает.Теперь, когда я перемещаю окно в (3000,0), оно перемещается в (4500,0).Кажется, мне как-то нужно масштабировать координаты, которые я передаю SetWindowPos(), но я понятия не имею, как.

m_previousContext = SetThreadDpiAwarenessContext(GetWindowDpiAwarenessContext(hwnd));
if(m_previousContext == NULL)
  Log::out<Log::Level::Error>("Failed to set thread dpi awareness context.");
SetWindowPos(hwnd, HWND_BOTTOM, 3000, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);

Кроме того, разве это не действительно неэффективно, если я регулярно изменяю размеры и перемещаю окна?

EDIT2: Я прикрепил ссылку на минимально работающий двоичный файл.Вы можете скачать его с Google Drive здесь .Требуется Windows 10, версия 1607 для запуска.Когда я запускаю его на вышеупомянутой установке с SetWindowPos.exe 002108B6 3000 0, вместо этого окно перемещается в (4500,0).

Ниже приведен код:

int main(int argc, char** argv)
{
  if(argc < 4)
  {
    std::cerr << "Usage: SetWindowPos.exe <HWND> <x> <y>" << std::endl;
    return 1;
  }
  HWND hwnd;
  int x, y;
  try
  {
    hwnd = (HWND)hexStrToInt(argv[1]); // I've omitted the implementation of hexStrToInt
    x = atoi(argv[2]);
    y = atoi(argv[3]);
  }
  catch(...)
  {
    std::cerr << "Invalid arguments." << std::endl;
    return 1;
  }
  if(IsWindow(hwnd) == FALSE)
  {
    std::cerr << "Invalid window handle " << argv[1] << "." << std::endl;
    return 1;
  }
  auto context = SetThreadDpiAwarenessContext(GetWindowDpiAwarenessContext(hwnd));
  SetWindowPos(hwnd, HWND_BOTTOM, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  SetThreadDpiAwarenessContext(context);
  return 0;
}

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Вам нужно не только установить режим распознавания потоков на одно и то же значение, вам также нужно установить для них значение DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, чтобы включить и разрешение dpi.

Установите его как в приложении, так и в целевом приложении.:

SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
...