WM_DPICHANGED循环调用,未从WM_GETDPISCALEDSIZE返回大小

时间:2018-09-05 09:09:28

标签: winapi highdpi

我试图使我们的WinAPI应用程序能够感知DPI,并遇到一个看似无限的循环,在该循环中,窗口不断接收WM_DPICHANGED。如文档所述,程序始终使用WM_DPICHANGED消息的lParam调用SetWindowPos。

我的显示器设置中,显示器1的右侧为1920x1080,缩放比例为100%,显示器2的左侧为底部,分辨率为3840x2160,缩放比例为150%。运行以下程序,移动窗口,使其跨过两个监视器,但缩放比例为100%。现在,抓住左侧监视器上的窗口,然后垂直上下移动窗口,以便在两种分辨率之间切换。在某个时候,它进入了一个循环,似乎使整个窗口管理器停滞了(ctrl-alt-del会中断它-不需要实际终止程序)。

在此循环中,在lParam中传递的矩形对于96和144 DPI的尺寸均为500x500! 为什么WM_DPICHANGED获取的矩形不是WM_GETDPISCALEDSIZE返回的矩形?

我知道我通过在较高DPI监视器上缩小窗口来做一些不寻常的事情(在实际应用中,我们的窗口具有复杂的布局,取决于分辨率而改变)。

这是为什么循环,我们如何避免DPI更改周期?

#include "stdafx.h"

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_GETDPISCALEDSIZE:
    {
        LPSIZE lpSize = (LPSIZE)lParam;
        int dpi = wParam;
        lpSize->cy = lpSize->cx = (dpi == 96 ? 200 : 500);
        return TRUE;
    }
    case WM_DPICHANGED:
    {
        LPRECT lpRect = (LPRECT)lParam;
        SetWindowPos(hWnd, nullptr, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, SWP_NOZORDER | SWP_NOACTIVATE);
        return 0;
    }
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

WCHAR szTitle[] = L"Test";                  // The title bar text
WCHAR szWindowClass[] = L"TESTCLASS";            // the main window class name

ATOM                MyRegisterClass(HINSTANCE);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    MyRegisterClass(hInstance);

   SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_VISIBLE,
      200, 200, 200, 200, nullptr, nullptr, hInstance, nullptr);

    MSG msg;

    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = nullptr;
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = nullptr;
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = nullptr;

    return RegisterClassExW(&wcex);
}

1 个答案:

答案 0 :(得分:0)

在这种情况下,通过检测wParam中的DPI是否与“ GetDpiForWindow , and ignoring WM_DPICHANGED”返回的DPI相匹配,似乎可以解决这种情况。