From b02aa1a12b6186552e792839a345083ea6218783 Mon Sep 17 00:00:00 2001 From: Lorenz Cuno Klopfenstein Date: Tue, 22 Oct 2013 01:14:01 +0200 Subject: [PATCH] Fixed client size <-> window size conversion to use official AdjustWindowRectEx Win32 API instead of handrolled difference computation. --- OnTopReplica/AspectRatioForm.cs | 43 +++++++++++-------- OnTopReplica/Native/Rectangle.cs | 11 +++++ OnTopReplica/Native/WindowMethods.cs | 57 ++++++++++++++++++-------- OnTopReplica/Platforms/WindowsSeven.cs | 23 ----------- 4 files changed, 77 insertions(+), 57 deletions(-) diff --git a/OnTopReplica/AspectRatioForm.cs b/OnTopReplica/AspectRatioForm.cs index 06e298d..87f99f7 100644 --- a/OnTopReplica/AspectRatioForm.cs +++ b/OnTopReplica/AspectRatioForm.cs @@ -116,7 +116,8 @@ namespace OnTopReplica { MinimumSize.Width); //Determine new height while keeping aspect ratio - int newHeight = (int)((newWidth - ExtraPadding.Horizontal - clientSizeConversionWidth) / AspectRatio) + ExtraPadding.Vertical + clientSizeConversionHeight; + var clientConversionDifference = ClientWindowDifference; + int newHeight = (int)((newWidth - ExtraPadding.Horizontal - clientConversionDifference.Width) / AspectRatio) + ExtraPadding.Vertical + clientConversionDifference.Height; //Apply and move form to recenter Size = new Size(newWidth, newHeight); @@ -161,11 +162,13 @@ namespace OnTopReplica { /// protected override void WndProc(ref Message m) { if (KeepAspectRatio && m.Msg == WM.SIZING) { + var clientSizeConversion = ClientWindowDifference; + var rc = (Native.NRectangle)Marshal.PtrToStructure(m.LParam, typeof(Native.NRectangle)); int res = m.WParam.ToInt32(); - int width = (rc.Right - rc.Left) - clientSizeConversionWidth - ExtraPadding.Horizontal; - int height = (rc.Bottom - rc.Top) - clientSizeConversionHeight - ExtraPadding.Vertical; + int width = (rc.Right - rc.Left) - clientSizeConversion.Width - ExtraPadding.Horizontal; + int height = (rc.Bottom - rc.Top) - clientSizeConversion.Height - ExtraPadding.Vertical; if (res == WMSZ.LEFT || res == WMSZ.RIGHT) { //Left or right resize, adjust top and bottom @@ -173,7 +176,7 @@ namespace OnTopReplica { int diffHeight = height - targetHeight; rc.Top += (int)(diffHeight / 2.0); - rc.Bottom = rc.Top + targetHeight + ExtraPadding.Vertical + clientSizeConversionHeight; + rc.Bottom = rc.Top + targetHeight + ExtraPadding.Vertical + clientSizeConversion.Height; } else if (res == WMSZ.TOP || res == WMSZ.BOTTOM) { //Up or down resize, adjust left and right @@ -181,15 +184,15 @@ namespace OnTopReplica { int diffWidth = width - targetWidth; rc.Left += (int)(diffWidth / 2.0); - rc.Right = rc.Left + targetWidth + ExtraPadding.Horizontal + clientSizeConversionWidth; + rc.Right = rc.Left + targetWidth + ExtraPadding.Horizontal + clientSizeConversion.Width; } else if (res == WMSZ.RIGHT + WMSZ.BOTTOM || res == WMSZ.LEFT + WMSZ.BOTTOM) { //Lower corner resize, adjust bottom - rc.Bottom = rc.Top + (int)(width / AspectRatio) + ExtraPadding.Vertical + clientSizeConversionHeight; + rc.Bottom = rc.Top + (int)(width / AspectRatio) + ExtraPadding.Vertical + clientSizeConversion.Height; } else if (res == WMSZ.LEFT + WMSZ.TOP || res == WMSZ.RIGHT + WMSZ.TOP) { //Upper corner resize, adjust top - rc.Top = rc.Bottom - (int)(width / AspectRatio) - ExtraPadding.Vertical - clientSizeConversionHeight; + rc.Top = rc.Bottom - (int)(width / AspectRatio) - ExtraPadding.Vertical - clientSizeConversion.Height; } Marshal.StructureToPtr(rc, m.LParam, false); @@ -202,15 +205,15 @@ namespace OnTopReplica { #region ClientSize/Size conversion helpers - int clientSizeConversionWidth, clientSizeConversionHeight; - /// /// Converts a client size measurement to a window size measurement. /// /// Size of the window's client area. /// Size of the whole window. public Size FromClientSizeToSize(Size clientSize) { - return new Size(clientSize.Width + clientSizeConversionWidth, clientSize.Height + clientSizeConversionHeight); + var difference = ClientWindowDifference; + + return new Size(clientSize.Width + difference.Width, clientSize.Height + difference.Height); } /// @@ -219,18 +222,24 @@ namespace OnTopReplica { /// Size of the whole window. /// Size of the window's client area. public Size FromSizeToClientSize(Size size) { - return new Size(size.Width - clientSizeConversionWidth, size.Height - clientSizeConversionHeight); - } + var difference = ClientWindowDifference; - protected override void OnShown(EventArgs e) { - base.OnShown(e); - - clientSizeConversionWidth = Size.Width - ClientSize.Width; - clientSizeConversionHeight = Size.Height - ClientSize.Height; + return new Size(size.Width - difference.Width, size.Height - difference.Height); } #endregion + /// + /// Gets the difference in pixels between a client size value and a window size value (depending on window decoration). + /// + protected Size ClientWindowDifference { + get { + long style = WindowMethods.GetWindowLong(this.Handle, WindowMethods.WindowLong.Style).ToInt64(); + long exStyle = WindowMethods.GetWindowLong(this.Handle, WindowMethods.WindowLong.ExStyle).ToInt64(); + return WindowMethods.ConvertClientToWindowRect(new NRectangle(0, 0, 0, 0), style, exStyle).Size; + } + } + } } diff --git a/OnTopReplica/Native/Rectangle.cs b/OnTopReplica/Native/Rectangle.cs index cb138c8..1166648 100644 --- a/OnTopReplica/Native/Rectangle.cs +++ b/OnTopReplica/Native/Rectangle.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; +using System.Drawing; namespace OnTopReplica.Native { + /// A native Rectangle Structure. [StructLayout(LayoutKind.Sequential)] struct NRectangle { @@ -52,4 +54,13 @@ namespace OnTopReplica.Native { } } + + static class NRectangleExtensions { + + public static NRectangle ToNativeRectangle(this Size size) { + return new NRectangle(0, 0, size.Width, size.Height); + } + + } + } diff --git a/OnTopReplica/Native/WindowMethods.cs b/OnTopReplica/Native/WindowMethods.cs index 56d315b..7345218 100644 --- a/OnTopReplica/Native/WindowMethods.cs +++ b/OnTopReplica/Native/WindowMethods.cs @@ -56,17 +56,6 @@ namespace OnTopReplica.Native { return String.Empty; } - const int MaxClassLength = 255; - - public static string GetWindowClass(IntPtr hwnd) { - var sb = new StringBuilder(MaxClassLength + 1); - RealGetWindowClass(hwnd, sb, MaxClassLength); - return sb.ToString(); - } - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern uint RealGetWindowClass(IntPtr hwnd, [Out] StringBuilder lpString, uint maxCount); - public enum WindowLong { WndProc = (-4), HInstance = (-6), @@ -77,11 +66,6 @@ namespace OnTopReplica.Native { Id = (-12) } - public enum ClassLong { - Icon = -14, - IconSmall = -34 - } - [Flags] public enum WindowStyles : long { None = 0, @@ -131,7 +115,23 @@ namespace OnTopReplica.Native { [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, WindowLong nIndex, IntPtr dwNewLong); - #region Class styles + #region Window class + + const int MaxClassLength = 255; + + public static string GetWindowClass(IntPtr hwnd) { + var sb = new StringBuilder(MaxClassLength + 1); + RealGetWindowClass(hwnd, sb, MaxClassLength); + return sb.ToString(); + } + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern uint RealGetWindowClass(IntPtr hwnd, [Out] StringBuilder lpString, uint maxCount); + + public enum ClassLong { + Icon = -14, + IconSmall = -34 + } [DllImport("user32.dll", EntryPoint = "GetClassLongPtrW")] static extern IntPtr GetClassLong64(IntPtr hWnd, int nIndex); @@ -153,5 +153,28 @@ namespace OnTopReplica.Native { [DllImport("user32.dll")] public static extern IntPtr GetMenu(IntPtr hwnd); + /// + /// Converts client size rectangle to window rectangle, according to window styles. + /// + /// Client area bounding box. + /// Style of window to compute. + /// Extended style of window to compute. + public static NRectangle ConvertClientToWindowRect(NRectangle clientRectangle, long windowStyle, long extendedWindowStyle) { + NRectangle tmp = clientRectangle; + if (AdjustWindowRectEx(ref tmp, windowStyle, false, extendedWindowStyle)) { + return tmp; + } + else { +#if DEBUG + throw new InvalidOperationException("Failed to convert client rectangle to window rectangle"); +#else + return clientRectangle; +#endif + } + } + + [DllImport("user32.dll")] + private static extern bool AdjustWindowRectEx(ref NRectangle clientToWindowRect, long windowStyle, bool hasMenu, long extendedWindowStyle); + } } diff --git a/OnTopReplica/Platforms/WindowsSeven.cs b/OnTopReplica/Platforms/WindowsSeven.cs index c24ee7c..4114f3b 100644 --- a/OnTopReplica/Platforms/WindowsSeven.cs +++ b/OnTopReplica/Platforms/WindowsSeven.cs @@ -33,29 +33,6 @@ namespace OnTopReplica.Platforms { form.Show(); } - /*public override void OnFormStateChange(MainForm form) { - //SetWindowStyle(form); - }*/ - - /// - /// Used to alter the window style. Not used anymore. - /// - private void SetWindowStyle(MainForm form) { - if (!form.FullscreenManager.IsFullscreen) { - //This hides the app from ALT+TAB - //Note that when minimized, it will be shown as an (ugly) minimized tool window - //thus we do not minimize, but set to transparent when hiding - long exStyle = WindowMethods.GetWindowLong(form.Handle, WindowMethods.WindowLong.ExStyle).ToInt64(); - - exStyle |= (long)(WindowMethods.WindowExStyles.ToolWindow); - //exStyle &= ~(long)(WindowMethods.WindowExStyles.AppWindow); - - WindowMethods.SetWindowLong(form.Handle, WindowMethods.WindowLong.ExStyle, new IntPtr(exStyle)); - - //WindowMethods.SetWindowLong(form.Handle, WindowMethods.WindowLong.HwndParent, WindowManagerMethods.GetDesktopWindow()); - } - } - } }