using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public static class DisplayFusionFunction
{
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
//some constants
const uint GW_HWNDNEXT = 2;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOACTIVATE = 0x0010;
private const int SWP_NOSENDCHANGING = 0x0400;
public static void Run(IntPtr windowHandle)
{
// Get the saved window info
Dictionary<IntPtr, WindowInfo> savedWindowInfo = new Dictionary<IntPtr, WindowInfo>();
foreach (WindowInfo info in System.Text.Json.JsonSerializer.Deserialize<List<WindowInfo>>(BFS.ScriptSettings.ReadValue("WindowInfoList")))
{
if (savedWindowInfo.ContainsKey(info.HandleAsPtr()))
continue;
savedWindowInfo.Add(info.HandleAsPtr(), info);
}
// A list to store the windows
List<IntPtr> windows = new List<IntPtr>();
// Enumerate through the monitors, starting with the focused window, and moving down
for (IntPtr window = BFS.Window.GetFocusedWindow(); ; window = GetWindow(window, GW_HWNDNEXT))
{
// Check to see if there are any windows left
if (window == IntPtr.Zero)
break;
// we don't care about windows we have no info about
if (!savedWindowInfo.ContainsKey(window))
continue;
// Store the window with its info
windows.Add(window);
}
// Bubble sort!
bool swapped;
for (int i = 0; i < windows.Count - 1; i++)
{
swapped = false;
for (int j = 0; j < windows.Count - i - 1; j++)
{
WindowInfo a = savedWindowInfo[windows[j]];
WindowInfo b = savedWindowInfo[windows[j + 1]];
if (a.ZOrder <= b.ZOrder)
continue;
swapped = true;
SwapWindowZOrder(a.HandleAsPtr(), b.HandleAsPtr());
windows[j] = b.HandleAsPtr();
windows[j + 1] = a.HandleAsPtr();
}
if (!swapped)
break;
}
// Restore state and positions
foreach (IntPtr window in windows)
{
WindowInfo saved = savedWindowInfo[window];
WindowInfo current = new WindowInfo(window, 0); // we don't care about the z-order here
// Debugging for IrfanView
string title = BFS.Window.GetText(window) ?? string.Empty;
if (title == "IrfanView")
{
BFS.Dialog.ShowMessageInfo($"Restoring window: IrfanView\nSaved Bounds: {saved.Bounds}\nCurrent Bounds: {current.Bounds}");
}
if (saved.State != current.State)
{
if (saved.State == FormWindowState.Normal)
BFS.Window.Restore(window);
if (saved.State == FormWindowState.Minimized)
BFS.Window.Minimize(window);
if (saved.State == FormWindowState.Maximized)
BFS.Window.Maximize(window);
}
if (saved.Bounds != current.Bounds)
{
BFS.Window.SetSizeAndLocation(window, saved.Bounds.X, saved.Bounds.Y, saved.Bounds.Width, saved.Bounds.Height);
// Debugging after restoring position and size
if (title == "IrfanView")
{
Rectangle newBounds = BFS.Window.GetBounds(window);
BFS.Dialog.ShowMessageInfo($"Restored window: IrfanView\nNew Bounds: {newBounds}");
}
}
}
}
// A method to swap two window z orders
private static void SwapWindowZOrder(IntPtr a, IntPtr b)
{
SetWindowPos(a, b, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
SetWindowPos(b, a, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
}
private static bool IsDisplayFusionWindowOrHiddenExplorerWindow(IntPtr window)
{
// Ignore any DisplayFusion windows (title bar buttons, etc.)
// Ignore pesky hidden explorer.exe windows
string windowClass = BFS.Window.GetClass(window);
if ((windowClass.StartsWith("DF", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("EdgeUiInputTopWndClass", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("EdgeUiInputWndClass", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("NativeHWNDHost", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("ModeInputWnd", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("MetroGhostWindow", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("ImmersiveLauncher", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("ApplicationManager_ImmersiveShellWindow", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("Shell_TrayWnd", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("WorkerW", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("Progman", StringComparison.OrdinalIgnoreCase)) ||
(windowClass.Equals("SearchPane", StringComparison.OrdinalIgnoreCase)))
{
return true;
}
return false;
}
public class WindowInfo
{
public long Handle { get; set; }
public FormWindowState State { get; set; }
public Rectangle Bounds { get; set; }
public int ZOrder { get; set; }
// for JSON deserialization
public WindowInfo() {}
public WindowInfo(IntPtr handle, int zOrder)
{
this.Handle = handle.ToInt64();
if (BFS.Window.IsMinimized(handle))
this.State = FormWindowState.Minimized;
else if (BFS.Window.IsMaximized(handle))
this.State = FormWindowState.Maximized;
else
this.State = FormWindowState.Normal;
this.Bounds = BFS.Window.GetBounds(handle);
this.ZOrder = zOrder;
}
public IntPtr HandleAsPtr()
{
return new IntPtr(this.Handle);
}
}
}