Я уже задавал подобный вопрос здесь , но теперь проблемы, кажется, немного другие, поэтому я решил, что создам новый вопрос для него.
Яиспользуя 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;
}