【问题标题】:DwmGetWindowAttribute returns 0 with PInvokeDwmGetWindowAttribute 使用 PInvoke 返回 0
【发布时间】:2016-07-31 15:17:05
【问题描述】:

我正在尝试通过捕获特定窗口来进行屏幕捕获,并且为了准确地确定要捕获的窗口的大小,我想使用 DwmGetWindowAttribute()。当我在 Windows 10 上使用 PInvoke 调用此函数时,Rect 结构始终为空,即使结果值为 0(成功)。传入的 Window 句柄也是有效的,因为有调用 GetWindowRect() 的后备代码可以工作(尽管存在边框问题)。

我有点不知所措。不久前我使用了相同的代码(也许在 Windows 8.1 上?),相同的代码似乎正在工作,但现在无论我做什么,对函数的调用总是返回一个空结构。

这是相关代码。

定义:

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


    [Flags]
    public enum DwmWindowAttribute : uint
    {
        DWMWA_NCRENDERING_ENABLED = 1,
        DWMWA_NCRENDERING_POLICY,
        DWMWA_TRANSITIONS_FORCEDISABLED,
        DWMWA_ALLOW_NCPAINT,
        DWMWA_CAPTION_BUTTON_BOUNDS,
        DWMWA_NONCLIENT_RTL_LAYOUT,
        DWMWA_FORCE_ICONIC_REPRESENTATION,
        DWMWA_FLIP3D_POLICY,
        DWMWA_EXTENDED_FRAME_BOUNDS,
        DWMWA_HAS_ICONIC_BITMAP,
        DWMWA_DISALLOW_PEEK,
        DWMWA_EXCLUDED_FROM_PEEK,
        DWMWA_CLOAK,
        DWMWA_CLOAKED,
        DWMWA_FREEZE_REPRESENTATION,
        DWMWA_LAST
    }

    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public Rectangle ToRectangle()
        {
            return Rectangle.FromLTRB(Left, Top, Right, Bottom);
        }
    }

执行捕获的代码:

    public static Rectangle GetWindowRectangle(IntPtr handle)
    {
        Rectangle rected = Rectangle.Empty;

        Rect rect = new Rect();
        if (Environment.OSVersion.Version.Major < 6)
        {
            GetWindowRect(handle, out rect);
            rected = rect.ToRectangle();
        }      
        else
        {

            int size = Marshal.SizeOf(typeof(Rect));
            int res = DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out rect, size);

            Debug.WriteLine(res.ToString("x") + " " + size + " " + handle + " " + (int) DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS);

            // allow returning of desktop and aero windows
            if (rected.Width == 0)
            {
                GetWindowRect(handle, out rect);
                rected = rect.ToRectangle();
                Debug.WriteLine("Using GetWindowRect");
            }
        }

        Debug.WriteLine(rected.ToString());
        return rected;
    }

感觉这里缺少一些简单的东西。有什么想法吗?

【问题讨论】:

  • 它工作正常,你的代码中有一个简单的错误。您必须在测试rected.Width 属性之前调用rect.ToRectangle()。赞成利用 C# 的明确分配跟踪功能,初始化 rected 变量是一个错误。
  • 呃。你是对的。想要回答这个问题吗?否则我可以将其删除为“愚蠢的用户错误”:-)
  • 我已经投票以“错字”结束。这对其他人没有帮助。
  • 它确实帮助了我。我得到了我需要的东西的工作样本:)

标签: c# windows pinvoke


【解决方案1】:

基于Rick Strahl 原始代码以及Hans Passant 更正,我创建了一个更紧凑的GetWindowsRectangle 版本。我在 Windows 10 上对其进行了测试,以下是代码以防将来对某人有所帮助:

public static Rectangle GetWindowRectangle(IntPtr handle)
    {
        Rect rect = new Rect();
                        
        if (Environment.OSVersion.Version.Major >= 6)
        {
            int size = Marshal.SizeOf(typeof(Rect));
            DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out rect, size);
        }
        else if (Environment.OSVersion.Version.Major < 6 || rect.ToRectangle().Width == 0)
        {
            GetWindowRect(handle, out rect);
        }

        return rect.ToRectangle();
    }

【讨论】:

    【解决方案2】:

    使用GetWindowRect而不是DwmGetWindowAttribute来接收窗口的RECT

    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
    

    【讨论】:

    • rect 不是空的,而是有错误的(偏移)坐标..
    猜你喜欢
    • 2023-04-09
    • 2011-09-25
    • 1970-01-01
    • 2010-09-27
    • 2021-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多