我正在创建一个使用 SetWindowPos() 从另一个进程移动/调整窗口大小的程序。我自己的程序是 PROCESS_PER_MONITOR_DPI_AWARE 。其他程序可以是 PROCESS_DPI_UNAWAREPROCESS_SYSTEM_DPI_AWAREPROCESS_PER_MONITOR_DPI_AWARE 中的任何内容。

因为我自己的程序是 PROCESS_PER_MONITOR_DPI_AWARE ,所以我传递给 SetWindowPos() 的坐标是物理坐标。我现在想要做的是 将客户区 的大小调整为 逻辑坐标 中的特定大小。

我试图做的是

  • 获取放置窗口的监视器的 DPI 作为 screenDPI
  • 获取目标窗口的 DPI 作为 windowDPI
  • 获取 scaleFactor 作为 screenDPI / windowDPI
  • 通过 scaleFactor
  • 缩放所需的客户区大小
  • 通过从窗口矩形大小中减去当前客户端矩形大小来计算窗口框架的额外大小。

  • 这在大多数情况下都有效,但是当我使用两个具有不同显示比例的屏幕时,然后
  • 如果我将窗口从一个屏幕移动到下一个屏幕,则窗口框架大小的计算将关闭。
  • 这对于使用 PROCESS_SYSTEM_DPI_AWARE 的应用程序失败,当窗口位于辅助屏幕上时(与使用 120dpi 的主屏幕相比,使用 96dpi)。这与窗口框架大小无关,我还不确定它为什么会失败,但是目标 xy 坐标被放大,以便窗口移到屏幕外。
  • 如果由于调整大小,窗口的中心改变了屏幕,会发生什么?那么 screenDPI 将不再正确,对吗?我将如何处理这种情况?

  • 我知道还有函数 AdjustWindowRectExForDpi ,但不知何故我无法让它正常工作。我应该传递给它的 dpi 值是多少?目标屏幕的dpi,目标窗口的dpi还是我自己程序的dpi?此外,此功能仅从 Windows 10 开始可用,那么我将如何在较旧的 Windows 客户端上处理它?

    我将不胜感激。谢谢!

    最佳答案



    您需要从一个屏幕移动到下一个屏幕的窗口的 DPI。

    代码示例:

    #include <Windows.h>
    
    LRESULT CALLBACK startup_window_procedure(HWND window, UINT message, WPARAM w_param, LPARAM l_param)
    {
        switch (message)
        {
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
    
        case WM_DPICHANGED:
        {
            // Resize the window
            RECT* new_rect = reinterpret_cast<RECT*>(l_param);
    
            if (!SetWindowPos(window, nullptr, new_rect->left, new_rect->top, new_rect->right - new_rect->left, new_rect->bottom - new_rect->top, SWP_NOZORDER | SWP_NOACTIVATE))
            {
                return 1;
            }
    
            return 0;
        }
        }
    
        return DefWindowProcW(window, message, w_param, l_param);
    }
    
    int CALLBACK wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR cmd_line, int cmd_show)
    {
        constexpr auto window_class_name = L"example_dialog";
        constexpr auto window_style = WS_OVERLAPPEDWINDOW;
    
        // Enable per-monitor DPI-awareness version 2
        if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
        {
            return 1;
        }
    
        // Create the window
        WNDCLASSEXW window_class;
        window_class.cbSize = sizeof(window_class);
        window_class.style = CS_HREDRAW | CS_VREDRAW;
        window_class.lpfnWndProc = startup_window_procedure;
        window_class.cbClsExtra = 0;
        window_class.cbWndExtra = 0;
        window_class.hInstance = instance;
        window_class.hIcon = nullptr;
        window_class.hCursor = nullptr;
        window_class.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
        window_class.lpszMenuName = nullptr;
        window_class.lpszClassName = window_class_name;
        window_class.hIconSm = nullptr;
    
        if (!RegisterClassExW(&window_class))
        {
            return 1;
        }
    
        HWND window = CreateWindowExW(0, window_class_name, L"Example window", window_style, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, instance, nullptr);
    
        if (!window)
        {
            return 1;
        }
    
        UINT dpi = GetDpiForWindow(window);
        float scaling_factor = static_cast<float>(dpi) / 96;
        // Actually set the appropriate window size
        RECT scale;
        scale.left = 0;
        scale.top = 0;
        scale.right = static_cast<LONG>(300 * scaling_factor);
        scale.bottom = static_cast<LONG>(150 * scaling_factor);
    
        if (!AdjustWindowRectExForDpi(&scale, window_style, false, 0, dpi))
        {
            return 1;
        }
    
        if (!SetWindowPos(window, nullptr, 0, 0, scale.right - scale.left, scale.bottom - scale.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE))
        {
            return 1;
        }
    
        ShowWindow(window, SW_SHOWNORMAL);
    
        // Message loop
        MSG message;
        int result;
    
        while ((result = GetMessageW(&message, nullptr, 0, 0)) != 0)
        {
            if (result == -1)
            {
                return 1;
            }
            else
            {
                TranslateMessage(&message);
                DispatchMessageW(&message);
            }
        }
    
        return static_cast<int>(message.wParam);
    }
    

    窗口可以从一个屏幕移动到下一个屏幕并成功重新计算窗口大小。

    关于c++ - SetWindowPos() 跨进程 DPI 感知,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54591457/

    10-09 08:07