C++ SetWindowPos()具有多个监视器和不同显示比例的交叉进程

C++ SetWindowPos()具有多个监视器和不同显示比例的交叉进程,c++,windows,winapi,dpi,multiple-monitors,C++,Windows,Winapi,Dpi,Multiple Monitors,我已经问了一个类似的问题,但现在问题似乎有点不同,所以我想我应该为它创建一个新的问题 我正在使用SetWindowPos()从另一个进程移动/调整窗口大小。只要所有屏幕都使用相同的显示比例,此功能就可以正常工作,但在以下情况下,它无法按预期工作: 主屏幕为(0,0),具有3440x1440和150%的缩放比例 二级屏幕位于(3440,0),具有900x1440和100%缩放 我的应用程序是PROCESS\u PER\u MONITOR\u DPI\u AWARE\u V2,目标应用程序是PRO

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

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

  • 主屏幕为(0,0),具有3440x1440和150%的缩放比例
  • 二级屏幕位于(3440,0),具有900x1440和100%缩放
  • 我的应用程序是
    PROCESS\u PER\u MONITOR\u DPI\u AWARE\u V2
    ,目标应用程序是
    PROCESS\u DPI\u UNAWARE
    (由Windows缩放)
现在,如果我移动一个窗口,使左上角在主屏幕上,而中心仍然在次屏幕上,例如到(3400,0)

然后就是这样:

  • 根据第二个屏幕的100%显示比例缩放窗口
  • 车窗未移动到(3300,0)。相反,它在
    WM_WINDOWPOSCHANGING
    消息中接收到的坐标是(2200,0)。坐标似乎缩小到逻辑坐标
因此,我无法将窗口移动到该位置。我尝试在传递给
SetWindowPos()
的坐标上使用
PhysicalToLogicalPointForPerMonitorDPI()
,但没有成功(它甚至没有更改坐标)

现在我似乎无法将窗口移动到任何位置,使左上角位于主屏幕上,但窗口的中心仍位于次屏幕上,因为窗口将缩小坐标,如果我手动放大坐标,然后我已经将窗口定位在第二个屏幕上,窗口不再应用缩放。即使我能够解决这个问题,手动计算缩放比例在两屏设置下也是可能的,但在更多屏幕上很快就会变得太复杂。那么,我怎样才能让它工作呢

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);


使用
SetThreadDpiAwarenessContext
将线程感知模式临时设置为与目标应用程序相同的值


谢谢您的回答。不幸的是,这仍然不起作用。有关详细信息,请参见我编辑的问题。更改上下文后,您需要重新读取新上下文中的所有监视器、窗口、指针坐标,计算新上下文中的坐标,并将其交给
SetWindowPos
(请记住新上下文)。从一个上下文到另一个上下文的计算可能很困难,因为可能存在间隙或重叠。正如您在第二次编辑中所看到的,我甚至没有读过任何监视器或类似的内容。您有没有发现这一点?不幸的是,没有。我很快会再次研究这个问题。我也在PermonitorPI的
物理点方面遇到问题。该函数不执行任何操作,即使它返回
TRUE
。所以我在Chromium源代码中搜索它,看看他们是如何使用它的。但事实证明他们根本不使用这个功能。相反,它们使用
GetDpiForMonitor
计算相应监视器的比例因子。
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);

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;
}