首页 > 解决方案 > SetWindowPos() 具有多个监视器和不同显示缩放比例的跨进程

问题描述

我已经在这里问了一个类似的问题,但现在问题似乎有点不同,所以我想我会为它创建一个新问题。

我正在使用SetWindowPos()从另一个进程移动/调整窗口大小。只要所有屏幕都使用相同的显示缩放比例,它就可以正常工作,但在以下情况下,它不能按预期工作:

现在,如果我移动一个窗口,使左上角在主屏幕上,而中心仍然在辅助屏幕上,例如到 (3400, 0)。

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

然后这就是发生的事情:

因此,我无法将窗口移动到该位置。我尝试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;
}

标签: c++windowswinapidpimultiple-monitors

解决方案



推荐阅读