我正在开发一个可识别dpi的winapi应用程序,但遇到一个问题,即无缘无故将其窗口缩放了两倍。似乎在创建应用程序窗口后两次应用了dpi缩放。这是我的代码。 首先,我使我的应用程序能够感知dpi:
::SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
然后我计算显示器的dpi比例,并考虑此比例创建一个500 x 500的窗口:
dpiScale = <get dpi scale using ::GetDpiForMonitor()> / 96.f;
hWnd = ::CreateWindow(..., 0, 0, 500 * dpiScale, 500 * dpiScale, ...);
我还希望窗口的最小大小为500 x 500:
case WM_GETMINMAXINFO:
{
MINMAXINFO* info = (MINMAXINFO*)lParam;
info->ptMinTrackSize.x = 500 * dpiScale;
info->ptMinTrackSize.y = 500 * dpiScale;
break;
}
然后我实现dpi更改事件处理:
case WM_DPICHANGED:
{
dpiScale = LOWORD(wParam) / 96.f;
RECT rect = *(RECT *)lParam;
::SetWindowPos(... rect ...);
break;
}
当我在高dpi的显示器上启动应用程序时,例如120(x1.25比例因子),应用程序窗口看起来比应有的大。我还尝试在每个WM_SIZE
消息上打印出窗口大小:
case WM_SIZE:
{
RECT r;
::GetWindowRect(hWnd, &r);
int width = (r.right - r.left);
int height = (r.bottom - r.top);
std::cout << "WM_SIZE " << width << " " << height << " scale factor: " << (width / 500.f) << std::endl;
break;
}
这就是我得到的:
WM_SIZE 625 625 scale factor: 1.25
WM_SIZE 781 781 scale factor: 1.562
请注意,只有两个地方可以手动应用dpi缩放:窗口创建和WM_GETMINMAXINFO
消息处理。我还尝试从::CreateWindow()
通话中删除dpi缩放比例,但它没有任何改变。
尽管我已经为应用程序设置了dpi意识,但是Windows似乎正在自动调整窗口大小。为什么会这样?我该如何解决?谢谢。
已更新:
我创建了一个最小的可复制示例,可以在这里找到:
https://gist.github.com/APodlinny/179b90b9e0d45ea9576d33dca2273dce
您可以使用摘要中的MSVC项目文件,也可以创建一个空的Win32 MSVC项目,添加main.cpp
源文件并确保:
*使用Windows SDK 8.1或更高版本(检查项目设置中的VC目录,即包含目录和库目录)
* shcore.lib
库在链接器中具有其他依赖关系
*链接器子系统为Console
也许在Windows 10中为应用程序启用了高dpi缩放?
我对此表示怀疑,因为我在_tWinMain(...)
函数的开头为应用程序明确设置了dpi意识。该应用程序兼容性设置中的“覆盖dpi缩放”选项也未选中。此外,窗口内容本身似乎也没有缩放。
主监视器与您的应用所在的监视器之间在缩放比例上是否有所不同?
是的,但是我认为这并不重要。我有两个监视器,并且已经以两种配置测试了我的应用程序: 1.在辅助监视器上创建辅助125%,主要100%窗口。 2.在主要监视器上创建次要125%,主要125%的窗口。 在这两种情况下,窗口都会缩放两次。
错误在其他代码中。将断点放在
::GetWindowRect(hWnd, &r);
处理程序中的WM_SIZE
上。启动调试器,当它在断点处停止时,使其再次运行。当它第二次停止时,检查调用堆栈以查找第二个WM_SIZE
的起源。
感谢提示!看来第二条WM_SIZE
消息是Windows发送的WM_WINDOWPOSCHANGED
消息引起的:
case WM_WINDOWPOSCHANGED:
{
WINDOWPOS* pos = (WINDOWPOS*)lParam;
std::cout << "WM_WINDOWPOSCHANGED " << pos->x << " " << pos->y << " " << pos->cx << " " << pos->cy << std::endl;
return DefWindowProc(hWnd, message, wParam, lParam);
}
WM_WINDOWPOSCHANGED 100 100 625 625
WM_SIZE 625 625 scale factor: 1.25
WM_WINDOWPOSCHANGED 100 100 781 781
WM_SIZE 781 781 scale factor: 1.562
第一对WM_WINDOWPOSCHANGED
/ WM_SIZE
是由::ShowWindow()
引起的,第二对可以追溯到::GetMessage()
,但是我不知道是什么原因造成的要发送的消息。