You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI3中获取窗口所属显示器信息的技术求助

在WinUI3中获取当前窗口所属显示器的对应信息(替代UWP的DisplayInformation.GetForCurrentView)

核心思路

通过Win32 API结合WinUI3窗口句柄,关联当前窗口到对应显示器,再提取所需的像素、DPI、物理尺寸等信息,同时利用WinUI3原生事件监听DPI变化。


步骤1:获取当前WinUI3窗口的HWND

WinUI3窗口可通过WindowNative.GetWindowHandle获取底层句柄,这是后续关联显示器的基础:

using WinRT.Interop;

// 在MainWindow类中
nint hwnd = WindowNative.GetWindowHandle(this);

步骤2:通过HWND获取对应显示器句柄

使用Win32的MonitorFromWindow获取当前窗口所属的显示器句柄(依赖CsWin32包):

using Windows.Win32;
using Windows.Win32.Graphics.Gdi;

HMONITOR hMonitor = PInvoke.MonitorFromWindow(
    hwnd, 
    MONITOR_FROM_WINDOW_FLAGS.MONITOR_DEFAULTTONEAREST
);

步骤3:获取屏幕原始像素宽高

通过GetMonitorInfoW提取显示器的物理像素范围:

MONITORINFOEX monitorInfo = new MONITORINFOEX();
monitorInfo.cbSize = (uint)Marshal.SizeOf(monitorInfo);
if (PInvoke.GetMonitorInfo(hMonitor, ref monitorInfo))
{
    int screenWidthRaw = monitorInfo.rcMonitor.Right - monitorInfo.rcMonitor.Left;
    int screenHeightRaw = monitorInfo.rcMonitor.Bottom - monitorInfo.rcMonitor.Top;
    // 对应UWP的ScreenWidthInRawPixels/ScreenHeightInRawPixels
}

步骤4:获取RawPixelsPerViewPixel(DPI缩放比)

可选择获取窗口DPI(和窗口绑定的缩放比)或显示器原生DPI:

// 获取窗口关联的DPI缩放比(和UWP的RawPixelsPerViewPixel一致)
uint dpiX, dpiY;
PInvoke.GetDpiForWindow(hwnd, out dpiX, out dpiY);
double rawPixelsPerViewPixel = dpiX / 96.0; // 96为标准DPI基准值

// 或者获取显示器原生DPI
PInvoke.GetDpiForMonitor(
    hMonitor, 
    MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, 
    out dpiX, 
    out dpiY
);

步骤5:获取显示器对角线尺寸(DiagonalSizeInInches)

通过DisplayConfigGetDeviceInfo获取物理尺寸,需先匹配当前显示器的DisplayConfig路径:

using Windows.Win32.Graphics.Display;
using System.Runtime.InteropServices;

DISPLAYCONFIG_TARGET_DEVICE_NAME targetDeviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
targetDeviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetDeviceName.header.size = (uint)Marshal.SizeOf(targetDeviceName);

// 枚举当前活跃的显示路径,匹配目标显示器
bool foundTarget = false;
uint pathCount, modeCount;
PInvoke.GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
DISPLAYCONFIG_PATH_INFO[] paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
DISPLAYCONFIG_MODE_INFO[] modes = new DISPLAYCONFIG_MODE_INFO[modeCount];

if (PInvoke.QueryDisplayConfig(
    QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, 
    ref pathCount, 
    paths, 
    ref modeCount, 
    modes, 
    IntPtr.Zero) == 0)
{
    foreach (var path in paths)
    {
        HMONITOR monitor = PInvoke.MonitorFromPoint(
            path.targetInfo.targetPosition, 
            MONITOR_FROM_WINDOW_FLAGS.MONITOR_DEFAULTTONEAREST
        );
        if (monitor == hMonitor)
        {
            targetDeviceName.header.adapterId = path.targetInfo.adapterId;
            targetDeviceName.header.id = path.targetInfo.id;
            foundTarget = true;
            break;
        }
    }
}

if (foundTarget && PInvoke.DisplayConfigGetDeviceInfo(ref targetDeviceName.header) == 0)
{
    // 物理尺寸单位为厘米,转换为英寸(1英寸=2.54厘米)
    double diagonalInches = targetDeviceName.monitorPhysicalSize.cx / 2.54;
    // 对应UWP的DiagonalSizeInInches
}

步骤6:监听DPI变化事件

直接使用WinUI3窗口原生的DpiChanged事件,替代UWP的DisplayInformation.DpiChanged:

// 在窗口构造函数或初始化逻辑中订阅
this.DpiChanged += MainWindow_DpiChanged;

private void MainWindow_DpiChanged(object sender, WindowDpiChangedEventArgs args)
{
    double newRawPixelsPerViewPixel = args.NewDpi / 96.0;
    // 处理DPI变化后的业务逻辑
}

注意事项

  • 确保已安装CsWin32 NuGet包,并在项目中启用Win32 API的生成(可通过项目属性配置)。
  • DisplayConfigGetDeviceInfo返回31(ERROR_GEN_FAILURE)通常是因为未正确设置DISPLAYCONFIG_DEVICE_INFO_HEADER的adapterId和id,必须通过枚举显示路径匹配当前显示器。
  • 多显示器场景下,MonitorFromWindow的MONITOR_DEFAULTTONEAREST参数会保证获取离窗口最近的显示器,避免错误关联。

内容的提问来源于stack exchange,提问作者Pavlo Datsiuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 14:30:54