7

SizableWindows 8 でフォーム ボーダー スタイルが設定された WinForms フォームを使用すると、DesktopBoundsプロパティは正しい値を示します。

ここに画像の説明を入力

対照的に、フォーム ボーダー スタイルが のFixedDialog場合、値は間違っています。

ここに画像の説明を入力

Windows XP では、値は常に正しいです。

ここに画像の説明を入力

ここに画像の説明を入力

私の質問は:

完全な非クライアント領域を含むウィンドウの実際のサイズを取得するには?

更新 1:

この SO questionに関連しているようです。ここでも、これが私の問題を解決するかどうかを試してみます。

更新 2:

完全を期すために、VMware Windows 7 の結果を次に示します。

ここに画像の説明を入力

ここに画像の説明を入力

更新 3:

DwmGetWindowAttribute最後に、関数をDWMWA_EXTENDED_FRAME_BOUNDSと一緒に使用することを含む解決策を見つけました。以下に回答を掲載します。

4

2 に答える 2

9

私自身の質問に答えるために、DwmGetWindowAttribute関数をと一緒に使用することを含む解決策を最終的に見つけましたDWMWA_EXTENDED_FRAME_BOUNDS

答えは、すべてのシステムで動作するように見える関数を提示するこのソース コードに触発されました。コアは関数です:

public static Rectangle GetWindowRectangle(IntPtr handle)
{
    if (Environment.OSVersion.Version.Major < 6)
    {
        return GetWindowRect(handle);
    }
    else
    {
        Rectangle rectangle;
        return DWMWA_EXTENDED_FRAME_BOUNDS(handle, out rectangle) 
                   ? rectangle 
                   : GetWindowRect(handle);
    }
}

完全なコードを以下に示します。

public static class WindowHelper
{
    // https://code.google.com/p/zscreen/source/browse/trunk/ZScreenLib/Global/GraphicsCore.cs?r=1349

    /// <summary>
    /// Get real window size, no matter whether Win XP, Win Vista, 7 or 8.
    /// </summary>
    public static Rectangle GetWindowRectangle(IntPtr handle)
    {
        if (Environment.OSVersion.Version.Major < 6)
        {
            return GetWindowRect(handle);
        }
        else
        {
            Rectangle rectangle;
            return DWMWA_EXTENDED_FRAME_BOUNDS(handle, out rectangle) ? rectangle : GetWindowRect(handle);
        }
    }

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

    private enum Dwmwindowattribute
    {
        DwmwaExtendedFrameBounds = 9
    }

    [Serializable, StructLayout(LayoutKind.Sequential)]
    private struct Rect
    {
        // ReSharper disable MemberCanBePrivate.Local
        // ReSharper disable FieldCanBeMadeReadOnly.Local
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
        // ReSharper restore FieldCanBeMadeReadOnly.Local
        // ReSharper restore MemberCanBePrivate.Local

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

    private static bool DWMWA_EXTENDED_FRAME_BOUNDS(IntPtr handle, out Rectangle rectangle)
    {
        Rect rect;
        var result = DwmGetWindowAttribute(handle, (int)Dwmwindowattribute.DwmwaExtendedFrameBounds,
            out rect, Marshal.SizeOf(typeof(Rect)));
        rectangle = rect.ToRectangle();
        return result >= 0;
    }

    [DllImport(@"user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);

    private static Rectangle GetWindowRect(IntPtr handle)
    {
        Rect rect;
        GetWindowRect(handle, out rect);
        return rect.ToRectangle();
    }
}
于 2013-05-10T16:13:34.217 に答える
-3

「間違っている」という言い方が正しいとは思いません。理解できない値が表示されていますが、それは必ずしも間違っているとは限りません。本当の問題は、ウィンドウの境界を取得することによって解決しようとしている実際の問題は何ですか?

Win32GetWindowRectメソッドを試しましたか? それは何を示しているのだろうか。

OS を検出し、これらを説明するハックの 1 つを試すことができます。

C# で OS を特定するには: http://support.microsoft.com/kb/304283 (このサンプルでは特に Windows 8 について言及していませんが、SDK が更新されていると想定しています)

于 2013-05-10T15:11:39.680 に答える