6502bench/CommonWPF/WindowPlacement.cs

130 lines
4.7 KiB
C#

/*
* 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);
}
}
}