最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

c# - How to convert a coord in native DPI to one in WPF logic DPI? - Stack Overflow

matteradmin2PV0评论

In the project I contribute to (C#, WPF) I need to position multiple OSD windows on multiple screens, e.g. top-left, center,bottom-right, etc.

I use the following code to get all screens' workarea and dpi.

public readonly struct ScreenInfo(Rect workArea, uint dpiX, uint dpiY, bool isPrimary)
{
    public Rect WorkArea { get; } = workArea;
    public uint DpiX { get; } = dpiX;
    public uint DpiY { get; } = dpiY;
    public bool IsPrimary { get; } = isPrimary;
}

public static void UpdateScreenInfos()
{
    Screens.Clear();
    EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnumProc, IntPtr.Zero);
}

[DllImport("user32.dll")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, EnumDisplayMonitorsDelegate lpfnEnum, IntPtr dwData);

private delegate bool EnumDisplayMonitorsDelegate(HMONITOR hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData);

private static bool MonitorEnumProc(HMONITOR hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData)
{
    MONITORINFO monitorInfo = new() { cbSize = (uint)Marshal.SizeOf<MONITORINFO>() };

    if (!PInvoke.GetMonitorInfo(hMonitor, ref monitorInfo))
        return true;

    if (!PInvoke.GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var dpiX, out var dpiY).Succeeded)
        return true;

    var workArea = monitorInfo.rcWork;
    var multiplierX = 96d / dpiX;
    var multiplierY = 96d / dpiY;

    Screens.Add(new ScreenInfo(
        new Rect(workArea.X * multiplierX, workArea.Y * multiplierY, workArea.Width * multiplierX, workArea.Height * multiplierY),
        dpiX, dpiY,
        (monitorInfo.dwFlags & PInvoke.MONITORINFOF_PRIMARY) != 0
    ));

    return true;
}

The codes above work pretty fine when zoom ratios of all screens are the same. But if I have for example two screens: one 2K resolution with 150% zoom ratio, the other 4K with 125%, workarea calculated by MonitorEnumProc has an offset on all screens except the primary one.

My question is, is there a safe and reliable solution to convert those coord in native DPI into logic DPI in WPF? It should work under multi-screen environment, also under multi-zoom-ratios.

Post a comment

comment list (0)

  1. No comments so far