我已经问了一个类似的问题here,但现在问题似乎有点不同,所以我想我会为它创建一个新问题。
我正在使用SetWindowPos()
从另一个进程移动/调整窗口大小。只要所有屏幕使用相同的显示缩放,这都可以正常工作,但在以下情况下,它无法按预期工作:
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);
然后就是这样:
WM_WINDOWPOSCHANGING
消息中接收的坐标是(2200,0)。坐标似乎缩小到逻辑坐标。因此,我无法将窗口移动到该位置。我试图在我传递给PhysicalToLogicalPointForPerMonitorDPI()
的坐标上使用SetWindowPos()
,但没有成功(它甚至没有改变坐标)。
现在好像我无法将窗口移动到任何位置,左上角位于主屏幕上,但窗口的中心仍在辅助屏幕上,因为Windows会缩小坐标,如果我手动缩放它们我已经将窗口放在第二个屏幕上,Windows不再应用缩放。即使我能够解决这个问题,也可以通过双屏幕设置手动计算缩放比例,但是对于更多的屏幕,很快就会变得过于复杂。那么,我该如何让它发挥作用?
编辑1:我试图按照建议使用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:我附加了一个最小工作二进制文件的链接。你可以download it from Google Drive here。它需要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;
}
使用SetThreadDpiAwarenessContext
将线程感知模式临时设置为与目标应用程序相同的值。
High-DPI Scaling Improvements for Desktop Applications in the Windows 10 Creators Update (1703)
您不仅需要将线程感知模式设置为相同的值,还需要将它们设置为DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
以启用dpi感知。
在应用程序和目标应用程序中设置它:
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);