GetWindowRect返回奇数值

时间:2016-02-19 17:18:25

标签: c# wpf winapi pinvoke

我希望有人能够帮助我,我在我的应用程序中有以下一些代码来获取一个Rect

var windowPosition = NativeMethods.GetWindowRect(this._hwnd);
return new Rect(windowPosition.Left, windowPosition.Top, windowPosition.Width, windowPosition.Height);

我在一些我为自定义窗口编写的代码中使用它,这是在WPF应用程序中,窗口是使用IWindowManager.OpenWindow打开的。

当我运行代码并打开窗口时,我在windowPosition对象中得到以下值,这是一个RECT

top = 1466, bottom = 785, left = 26, right = 26, width = 0, height = -681

我看不出在RECT中以这些奇数值结束的代码有什么问题,结果我在下一行得到ArgumentException

我也尝试将此窗口作为主应用程序窗口运行,我遇到了同样的问题,应用程序正在使用MVVM和Caliburn Micro,虽然我不确定为什么会产生影响。

根据要求,RECT结构定义如下:

[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
    public void Offset(int dx, int dy)
    {
        this.Left += dx;
        this.Top += dy;
        this.Right += dx;
        this.Bottom += dy;
    }

    public int Left { get; set; }

    public int Top { get; set; }

    public int Right { get; set; }

    public int Bottom { get; set; }

    public int Width
    {
        get
        {
            return this.Right - this.Left;
        }
    }

    public int Height
    {
        get
        {
            return this.Bottom - this.Top;
        }
    }

    public POINT Position
    {
        get
        {
            return new POINT { x = this.Left, y = this.Top };
        }
    }

    public SIZE Size
    {
        get
        {
            return new SIZE { cx = this.Width, cy = this.Height };
        }
    }
}

和NativeMethods的GetWindowRect方法:

    [DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowRectInternal(IntPtr hWnd, out RECT lpRect);

    public static RECT GetWindowRect(IntPtr hwnd)
    {
        RECT rc;
        if (!GetWindowRectInternal(hwnd, out rc))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        return rc;
    }

我正在使用hWnd访问WindowInteropHelper(window).Handle,我忽略了包含NativeMethods中的公共方法,并且现在包含了这些方法,为浪费时间道歉。

1 个答案:

答案 0 :(得分:3)

正如各个评论者多次指出的那样,您的RECT结构的成员声明的顺序错误。 Win32 RECT structure按其lefttoprightbottom边界定义了一个矩形。右边界和底边界位于矩形之外(换句话说,矩形为end-point exclusive)。

因此,您需要修复结构定义:

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
   // Data members, in order, matching the Win32 RECT structure:
   public int Left;
   public int Top;
   public int Right;
   public int Bottom;

   // Constructor:
   public RECT(int left, int top, int right, int bottom)
   {
     this.Left  = left;
     this.Top   = top;
     this.Right = right;
     this.Bottom = bottom;
   }

   // Convenience properties:

   public int Width
   {
     get  { return this.Right - this.Left; }
     set  { this.Right = value + this.Left; }
   }

   public int Height
   {
     get  { return this.Bottom - this.Top; }
     set  { this.Bottom = value + this.Top; }
   }

   // Conversion helper functions:    

  public System.Drawing.Point Position
  {
     get  { return new System.Drawing.Point(this.Left, this.Top); }
  }

  public System.Drawing.Size Size
  {
     get  { return new System.Drawing.Size(this.Width, this.Height); }
  }
}

您还需要确保正确定义了POINTSIZE结构。或者,由于System.Drawing.PointSystem.Drawing.Size结构与本机类型100%兼容,因此只需使用它们(作为上述RECT结构中的转换函数)。

值得指出的是一个名为pinvoke.net的网站的存在,这是一个P / Invoke签名的协作编辑(维基式)存储库 - 包括结构和功能。在早期,定义并不完全值得信赖,但我认为它们正在变得更好。 (几年前我停止写这些内容并且没有跟上网站的进度。至少它的RECT structure是正确的。)

GetWindowRect结构的P / Invoke定义是正确的,但您显示的代码将无法编译。没有GetWindowRectInternal功能。你需要这样的东西:

[DllImport("user32.dll", SetLastError = true, EntryPoint="GetWindowRect")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRectInternal(IntPtr hWnd, out RECT lpRect);

public static RECT GetWindowRect(IntPtr hWnd)
{
    RECT rc;
    if (!GetWindowRectInternal(hWnd, out rc))
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }
    return rc;
}