1. 程式人生 > 其它 >Win10下獲取正確的視窗尺寸

Win10下獲取正確的視窗尺寸

參考

Retrieve Window Size without Windows Shadows
DwmGetWindowAttribute (dwmapi)

程式碼

  // 呼叫DwmGetWindowAttribute
  DwmGetWindowAttribute(this.Handle,
                        DWMWINDOWATTRIBUTE.ExtendedFrameBounds,
                        out rect,
                        Marshal.SizeOf(typeof(RECT)));
  // 列舉、結構體、API定義
  enum DWMWINDOWATTRIBUTE : uint
  {
    NCRenderingEnabled = 1,
    NCRenderingPolicy,
    TransitionsForceDisabled,
    AllowNCPaint,
    CaptionButtonBounds,
    NonClientRtlLayout,
    ForceIconicRepresentation,
    Flip3DPolicy,
    ExtendedFrameBounds,
    HasIconicBitmap,
    DisallowPeek,
    ExcludedFromPeek,
    Cloak,
    Cloaked,
    FreezeRepresentation
  }

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

    public RECT(int left, int top, int right, int bottom)
    {
      Left = left;
      Top = top;
      Right = right;
      Bottom = bottom;
    }

    public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { }

    public int X
    {
      get { return Left; }
      set { Right -= (Left - value); Left = value; }
    }

    public int Y
    {
      get { return Top; }
      set { Bottom -= (Top - value); Top = value; }
    }

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

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

    public System.Drawing.Point Location
    {
      get { return new System.Drawing.Point(Left, Top); }
      set { X = value.X; Y = value.Y; }
    }

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

    public static implicit operator System.Drawing.Rectangle(RECT r)
    {
      return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
    }

    public static implicit operator RECT(System.Drawing.Rectangle r)
    {
      return new RECT(r);
    }

    public static bool operator ==(RECT r1, RECT r2)
    {
      return r1.Equals(r2);
    }

    public static bool operator !=(RECT r1, RECT r2)
    {
      return !r1.Equals(r2);
    }

    public bool Equals(RECT r)
    {
      return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom;
    }

    public override bool Equals(object obj)
    {
      if (obj is RECT)
        return Equals((RECT)obj);
      else if (obj is System.Drawing.Rectangle)
        return Equals(new RECT((System.Drawing.Rectangle)obj));
      return false;
    }

    public override int GetHashCode()
    {
      return ((System.Drawing.Rectangle)this).GetHashCode();
    }

    public override string ToString()
    {
      return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
    }
  }

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

總結

和GetWindowRect比較,DwmGetWindowAttribute能在Win10下獲取視窗的實際尺寸。
從下表的資料比較中可以看出,非最大化時GetWindowRect計算了視窗左、右、下“多餘的部分”的尺寸,都是7個畫素。最大化時GetWindowRect計算了視窗左、右、上、下“多餘的部分”的尺寸,都是8個畫素。


非最大化

API LEFT TOP WIDTH HEIGHT
GetWindowRect 156 156 472 254
DwmGetWindowAttribute 163 156 458 247

最大化

API LEFT TOP WIDTH HEIGHT
GetWindowRect -8 -8 1936 1015
DwmGetWindowAttribute 0 0 1920 999