using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace Back2Base { static class Back2BaseProgram { static readonly string progver = "1.00"; static readonly int screenwidth = Screen.PrimaryScreen.WorkingArea.Width; static readonly int screenheight = Screen.PrimaryScreen.WorkingArea.Height; static bool includeminimized = false; static bool includeanonymous = false; [STAThread] static int Main( ) { Application.EnableVisualStyles( ); Application.SetCompatibleTextRenderingDefault( false ); #region Parse Command Line foreach ( string arg in Environment.CommandLine.Split( ' ' ).Skip( 1 ) ) { switch ( arg.ToUpper( ) ) { case "": break; case "/?": return ShowHelp( ); case "/IA": if ( includeanonymous ) { return ShowHelp( "Duplicate command line switch /IA" ); } includeanonymous = true; break; case "/IM": if ( includeminimized ) { return ShowHelp( "Duplicate command line switch /IM" ); } includeminimized = true; break; default: return ShowHelp( "Invalid command line argument \"{0}\"", arg ); } } #endregion Parse Command Line // List active windows GetDesktopWindowHandlesAndTitles( out windows ); #region Restore Minimized Windows // First restore/maximize any minimized window(s) that should be included foreach ( IntPtr handle in windows.Keys ) { if ( windows[handle] != "(no title)" || includeanonymous ) { if ( !IsIconic( handle ) || includeminimized ) { if ( IsIconic( handle ) && includeminimized ) { ShowWindow( handle, SW_SHOWMAXIMIZED ); //ShowWindow( handle, SW_SHOWMAXIMIZED ); } } } } #endregion Restore Minimized Windows #region Move Windows to Primary Monitor // Next move the window(s) to the primary monitor int count = 0; foreach ( IntPtr handle in windows.Keys ) { if ( windows[handle] != "(no title)" || includeanonymous ) { if ( !IsIconic( handle ) || includeminimized ) { RECT rect = new RECT( ); if ( GetWindowRect( handle, ref rect ) ) { if ( ( rect.Left > screenwidth || rect.Right < 20 || rect.Top > screenheight || rect.Bottom < 20 ) && ( rect.Left != 0 && rect.Top != 0 ) ) { int width = rect.Right - rect.Left; int height = rect.Bottom - rect.Top; bool repaint = true; if ( MoveWindow( handle, 0, 0, width, height, repaint ) ) { count += 1; } } } } } } #endregion Move Windows to Primary Monitor return count; } #region Check If Minimized [DllImport( "user32.dll" )] [return: MarshalAs( UnmanagedType.Bool )] static extern bool IsIconic( IntPtr hWnd ); // true if window is minimized #endregion Check If Minimized #region Get Window Size // Get window position and size // https://stackoverflow.com/a/1434577 [DllImport( "user32.dll", SetLastError = true )] [return: MarshalAs( UnmanagedType.Bool )] static extern bool GetWindowRect( IntPtr hWnd, ref RECT lpRect ); [StructLayout( LayoutKind.Sequential )] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } #endregion Get Window Size #region List Desktop Windows // Based on code by Rod Stephens // List desktop windows in C# // http://csharphelper.com/blog/2016/08/list-desktop-windows-in-c/ [DllImport( "user32.dll" )] [return: MarshalAs( UnmanagedType.Bool )] private static extern bool IsWindowVisible( IntPtr hWnd ); [DllImport( "user32.dll", EntryPoint = "GetWindowText", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true )] private static extern int GetWindowText( IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount ); [DllImport( "user32.dll", EntryPoint = "EnumDesktopWindows", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true )] private static extern bool EnumDesktopWindows( IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam ); // Define the callback delegate's type. private delegate bool EnumDelegate( IntPtr hWnd, int lParam ); // Save window titles and handles in Dictionary private static Dictionary windows; // Return a list of the desktop windows' handles and titles. public static void GetDesktopWindowHandlesAndTitles( out Dictionary windowslist ) { windowslist = new Dictionary( ); if ( !EnumDesktopWindows( IntPtr.Zero, FilterCallback, IntPtr.Zero ) ) { windowslist = null; } else { windowslist = windows; } } // We use this function to filter windows // This version selects visible windows that aren't minimized private static bool FilterCallback( IntPtr hWnd, int lParam ) { // Get the window's title StringBuilder sb_title = new StringBuilder( 1024 ); int _ = GetWindowText( hWnd, sb_title, sb_title.Capacity ); string title = sb_title.ToString( ); // If the window is visible and has a title, save it. if ( IsWindowVisible( hWnd ) ) { if ( string.IsNullOrEmpty( title ) ) { title = "(no title)"; } windows.Add( hWnd, title ); } // Return true to indicate that we should continue enumerating windows return true; } #endregion List Desktop Windows #region Move Window // Based on code by Roberto Luis Bisb\u00E9 // Moving windows programatically with Windows API, the path to WinResize // https://rlbisbe.net/2013/11/19/moving-windows-programatically-with-windows-api-the-path-to-winresize/ [DllImport( "user32.dll" )] public static extern bool MoveWindow( IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint ); #endregion Move Window #region Restore Window // private const int SW_SHOWNORMAL = 1; // private const int SW_SHOWMINIMIZED = 2; private const int SW_SHOWMAXIMIZED = 3; [DllImport( "user32.dll" )] private static extern bool ShowWindow( IntPtr hWnd, int nCmdShow ); [DllImport( "user32.dll" )] private static extern bool ShowWindowAsync( IntPtr hWnd, int nCmdShow ); #endregion Restore Window #region Error handling public static int ShowHelp( params string[] errmsg ) { string helptext = string.Empty; string title = "Back2Base, Version " + progver; MessageBoxIcon icon = MessageBoxIcon.Information; #region Error Message if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); helptext += "\nERROR:\t" + string.Format( errmsg[0], errargs.ToArray( ) ) + "\n\n"; title = "Error"; icon = MessageBoxIcon.Error; } #endregion Error Message #region Help Text /* Back2Base.exe, Version 1.00 Move out-of-sight windows back to the primary screen Usage: Back2Base [ /IA ] [ /IM ] Options: /IA Include Anonymous windows, i.e. those without title /IM Include Minimized windows Credits: Get window position and size https://stackoverflow.com/a/1434577 List desktop windows based on code by Rod Stephens http://csharphelper.com/blog/2016/08/list-desktop-windows-in-c/ Moving windows based on code by Roberto Luis Bisb\u00E9 https://rlbisbe.net/2013/11/19/moving-windows-programatically-with-windows-api-the-path-to-winresize/ Notes: This is a GUI version of CatchStrayWindows.exe; the only visible output will be error messages. Return code equals number of moved windows, or -1 in case of errors. Written by Rob van der Woude https://www.robvanderwoude.com */ #endregion Help Text #region Display Help Text helptext += "Back2Base.exe, Version " + progver; helptext += "\nMove out-of-sight windows back to the primary screen"; helptext += "\n\nOptions:\n======\n\n/IA\tInclude Anonymous windows, i.e. those without title"; helptext += "\n/IM\tInclude Minimized windows"; helptext += "\n\nCredits:\n=====\n\nGet window position and size:"; helptext += "\nhttps://stackoverflow.com/a/1434577"; helptext += "\n\nList desktop windows based on code by Rod Stephens:"; helptext += "\nhttp://csharphelper.com/blog/2016/08/list-desktop-windows-in-c/"; helptext += "\n\nMoving windows based on code by Roberto Luis Bisb\u00E9:"; helptext += "\nhttps://rlbisbe.net/2013/11/19/moving-windows-programatically-with-windows-api-the-path-to-winresize/"; helptext += "\n\nNotes:\n====\n\nThis is a GUI version of CatchStrayWindows.exe; the only visible output will be error messages."; helptext += "\n\nReturn code equals number of moved windows, or -1 in case of errors."; helptext += "\n\nWritten by Rob van der Woude"; helptext += "\nhttps://www.robvanderwoude.com"; MessageBox.Show( helptext, title, MessageBoxButtons.OK, icon, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly | MessageBoxOptions.ServiceNotification ); #endregion Display Help Text return -1; } #endregion Error handling } }