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

C# Winforms调用GetWindowRect等API获取窗口位置尺寸的异常问题求解

解决方案

核心逻辑

通过组合不同API的能力静默处理所有场景,完全不需要提前恢复最小化窗口:

  • 先通过GetWindowPlacement判断窗口当前是否为最小化状态,无需触发窗口恢复即可拿到状态信息
  • 非最小化窗口直接调用DwmGetWindowAttribute获取EXTENDED_FRAME_BOUNDS属性值,得到排除阴影的准确窗口坐标
  • 最小化窗口直接读取GetWindowPlacement返回结构体中的rcNormalPosition字段,该字段存储的是窗口还原后的无阴影偏移的正常位置坐标

DPI适配处理

首先在项目的应用程序清单(manifest)中开启高DPI感知,避免系统自动缩放导致的坐标偏移。如果需要兼容不同DPI感知级别的目标窗口,调用GetDpiForWindow获取目标窗口的DPI值,按比例将逻辑坐标转换为物理屏幕坐标即可,转换公式为:
物理坐标值 = 逻辑坐标值 * 目标窗口DPI / 96

完整实现示例

using System;
using System.Runtime.InteropServices;

// Rect结构体定义
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
    public int Width => Right - Left;
    public int Height => Bottom - Top;
}

// WindowPlacement结构体定义
[StructLayout(LayoutKind.Sequential)]
public struct WindowPlacement
{
    public int length;
    public int flags;
    public int showCmd;
    public Point ptMinPosition;
    public Point ptMaxPosition;
    public Rect rcNormalPosition;
}

[StructLayout(LayoutKind.Sequential)]
public struct Point
{
    public int X;
    public int Y;
}

public static class WindowApi
{
    private const int SW_SHOWMINIMIZED = 2;
    private const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;

    [DllImport("user32.dll")]
    private static extern bool GetWindowPlacement(IntPtr hWnd, out WindowPlacement lpwndpl);

    [DllImport("dwmapi.dll")]
    private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);

    [DllImport("user32.dll")]
    public static extern uint GetDpiForWindow(IntPtr hWnd);

    // 封装的获取窗口实际坐标方法
    public static bool GetWindowActualRect(IntPtr hWnd, out Rect rect)
    {
        rect = default;
        WindowPlacement wp = default;
        wp.length = Marshal.SizeOf(wp);

        if (!GetWindowPlacement(hWnd, out wp))
            return false;

        // 窗口是最小化状态,直接取正常位置矩形
        if (wp.showCmd == SW_SHOWMINIMIZED)
        {
            rect = wp.rcNormalPosition;
            return true;
        }

        // 非最小化状态,调用DWM API取无阴影坐标
        int dwmResult = DwmGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, out rect, Marshal.SizeOf(typeof(Rect)));
        return dwmResult == 0;
    }
}

兼容注意事项

如果需要兼容Windows 7以下系统(DWM API不可用),可以在DwmGetWindowAttribute调用失败后,回退到GetWindowRect获取坐标后手动减去系统边框偏移量:Windows 7及以上系统默认窗口阴影偏移为左右各7px、底部7px,对应减去即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:27:04