SetWindowPos()跨进程DPI感知 [英] SetWindowPos() cross-process DPI aware

查看:174
本文介绍了SetWindowPos()跨进程DPI感知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am creating a program that moves/resizes windows from another process with SetWindowPos(). My own program is PROCESS_PER_MONITOR_DPI_AWARE. The other programs could be anything from PROCESS_DPI_UNAWARE, PROCESS_SYSTEM_DPI_AWARE or PROCESS_PER_MONITOR_DPI_AWARE.

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

Because my own program is PROCESS_PER_MONITOR_DPI_AWARE, the coordinates I pass to SetWindowPos() are in physical coordinates. What I now want to do is resize the client area to a specific size in logical coordinates.

我要做什么


  1. 获取放置窗口的监视器的DPI为 screenDPI

  2. 获取目标窗口的DPI作为 windowDPI

  3. 获取 scaleFactor 作为 screenDPI / windowDPI

  4. 缩放所需的客户区域大小 scaleFactor

  5. 通过从窗口矩形大小中减去当前客户端矩形大小来计算窗口框架的额外大小。

  1. Get the DPI of the monitor where the window is placed as screenDPI.
  2. Get the DPI of the target window as windowDPI.
  3. Get scaleFactor as screenDPI / windowDPI.
  4. Scale the desired client area size by scaleFactor
  5. Calculated the extra size for the window frame by subtracting the current client rect size from the window rect size.

多数情况下有效,但是当我使用两个显示比例不同的屏幕时,

This works for the most part, but when I am using two screens with different display scaling, then


  • 如果将窗口从一个屏幕移到另一个屏幕,则窗口框架大小的计算将关闭。

  • 对于使用以下应用程序的应用程序将失败 PROCESS_SYSTEM_DPI_AWARE ,当窗口位于辅助屏幕上(与使用120dpi的主屏幕相比,它使用96dpi)。这与窗口框架的大小无关,我不确定为什么它会失败,但是目标 x y 坐标会按比例放大,以便将窗口移出屏幕。

  • 如果由于调整大小而使窗口的中心改变了屏幕,会发生什么情况?然后 screenDPI 将不再正确,对吧?我将如何处理这种情况?

  • the calculation of the window frame size is off if I move the window from one screen to the next.
  • this fails for an application that uses PROCESS_SYSTEM_DPI_AWARE, when the window is located on the secondary screen (which uses 96dpi compared to the primary screen with 120dpi). This has nothing to do with the window frame size and I am not yet sure why exactly it fails, but the target x and y coordinates are scaled up so that the window is moved offscreen.
  • what happens if, because of the resize, the center of the window changes the screen? Then the screenDPI will no longer be correct, right? How would I handle that case?

我知道也有函数 AdjustWindowRectExForDpi ,但是以某种方式我无法使其正常工作。我应该传递给它的 dpi 值是多少?目标屏幕的dpi,目标窗口的dpi或我自己的程序的dpi?另外,此功能仅在Windows 10及更高版本中可用,因此我将如何在较旧的Windows客户端上处理该功能?

I know that there is also the function AdjustWindowRectExForDpi, but somehow I can't get it to work properly. What is the dpi value I am supposed to pass to it? The dpi of the target screen, the dpi of the target window or the dpi of my own program? Additionally, this function is only available from Windows 10 onwards, so how would I handle it on an older Windows client?

我希望对此有所帮助。谢谢!

I would appreciate some help with this. Thanks!

推荐答案


我应该传递给它的dpi值是多少?目标屏幕的dpi,目标窗口的dpi还是我自己的程序的dpi?

DPI您需要从一个窗口移到另一个窗口。

The DPI of the window you need to move from one screen to the next.

代码示例:

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

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

The windows can move from one screen to the next and recalculate window size successfully.

这篇关于SetWindowPos()跨进程DPI感知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆