/* * This comes from a blog entry, posted by RandomEngy on March 8 2010: * https://blogs.msdn.microsoft.com/davidrickard/2010/03/08/saving-window-size-and-location-in-wpf-and-winforms/ * (see https://stackoverflow.com/a/2406604/294248 for discussion) * * Saving and restoring a window's size and position can be tricky when there are multiple * displays involved. This uses the Win32 system functions to do the job properly and * consistently. (In theory.) * * The code works for WinForms (save on FormClosing, restore on Load, using the native handle * from the Handle property) and WPF (use the Window extension methods provided below, in * Closing and SourceInitialized). Besides convenience, it has the added benefit of being able * to capture the non-maximized values for a maximized window. */ using System; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Windows; using System.Windows.Interop; using System.Xml; using System.Xml.Serialization; namespace CommonWPF { // RECT structure required by WINDOWPLACEMENT structure [Serializable] [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; public RECT(int left, int top, int right, int bottom) { this.Left = left; this.Top = top; this.Right = right; this.Bottom = bottom; } } // POINT structure required by WINDOWPLACEMENT structure [Serializable] [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; public POINT(int x, int y) { this.X = x; this.Y = y; } } // WINDOWPLACEMENT stores the position, size, and state of a window [Serializable] [StructLayout(LayoutKind.Sequential)] public struct WINDOWPLACEMENT { public int length; public int flags; public int showCmd; public POINT minPosition; public POINT maxPosition; public RECT normalPosition; } public static class WindowPlacement { private static Encoding encoding = new UTF8Encoding(); private static XmlSerializer serializer = new XmlSerializer(typeof(WINDOWPLACEMENT)); [DllImport("user32.dll")] private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl); [DllImport("user32.dll")] private static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl); private const int SW_SHOWNORMAL = 1; private const int SW_SHOWMINIMIZED = 2; public static void SetPlacement(IntPtr windowHandle, string placementXml) { if (string.IsNullOrEmpty(placementXml)) { return; } WINDOWPLACEMENT placement; byte[] xmlBytes = encoding.GetBytes(placementXml); try { using (MemoryStream memoryStream = new MemoryStream(xmlBytes)) { placement = (WINDOWPLACEMENT)serializer.Deserialize(memoryStream); } placement.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); placement.flags = 0; placement.showCmd = (placement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : placement.showCmd); SetWindowPlacement(windowHandle, ref placement); } catch (InvalidOperationException) { // Parsing placement XML failed. Fail silently. } } public static string GetPlacement(IntPtr windowHandle) { WINDOWPLACEMENT placement = new WINDOWPLACEMENT(); GetWindowPlacement(windowHandle, out placement); using (MemoryStream memoryStream = new MemoryStream()) { using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8)) { serializer.Serialize(xmlTextWriter, placement); byte[] xmlBytes = memoryStream.ToArray(); return encoding.GetString(xmlBytes); } } } // // Extension methods for WPF. // // Call from Closing event. Returns XML string with placement info. public static string GetPlacement(this Window window) { return GetPlacement(new WindowInteropHelper(window).Handle); } // Call from SourceInitialized event, passing in string from GetPlacement(). public static void SetPlacement(this Window window, string placementXml) { SetPlacement(new WindowInteropHelper(window).Handle, placementXml); } } }