【问题标题】:GetWindowRect returns odd values [closed]GetWindowRect 返回奇数值
【发布时间】:2016-02-19 17:18:25
【问题描述】:

我希望有人能帮我解决这个问题,我的应用程序中有以下代码,可以让我获得一个 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;
    }

我正在使用 WindowInteropHelper(window).Handle 访问 hWnd,我忽略了包含来自 NativeMethods 的公共方法,现在已经包含了,为浪费时间道歉。

【问题讨论】:

  • RECT 没有宽度或高度属性,显着增加了您刚刚声明错误的几率。奇怪你没有发布相关代码。
  • 向我们展示您如何定义 GetWindowRect 和您的 RECT 结构。
  • 它是 let-top-right-bottom,而不是 left-right-top-bottom。
  • 今晚我会改变它并试一试,但为什么会有不同呢?
  • 您发布了伪造的代码。这是对时间的巨大浪费。请发帖minimal reproducible example

标签: c# wpf winapi pinvoke


【解决方案1】:

正如各种评论者多次指出的那样,您的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 的网站,这是一个协作编辑(wiki 风格)的 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;
}

【讨论】:

  • 意识到我发布的代码中有错字,因此已更正,并更正了我的 RECT 定义,想了解为什么这四个属性的位置很重要?
  • 您正在与本机代码进行互操作,@Neil。您正在调用的 Win32 函数(如 GetWindowRect)期望处理 RECT 结构。这就是他们的编写方式,它是他们 ABI 的一部分。 RECT 结构以特定方式定义,其成员按特定顺序。如果你定义一个不同的结构,它的成员有不同的顺序,并将它传递给那些函数,他们不会知道他们被欺骗了。他们会将其视为RECT 结构,但它不会真正成为一个结构,因此您会得到错误的结果。这就像恶作剧打电话给某人。
  • 注意这里的结构是如何声明的[StructLayout(LayoutKind.Sequential)]。这样可以防止编译器重新排列成员的顺序,并提醒您顺序很重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-30
  • 2012-06-21
  • 2019-04-24
  • 2023-02-07
相关资源
最近更新 更多