Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for catchstraywindows.cs

(view source code of catchstraywindows.cs as plain text)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Text;
  5. using System.Windows.Forms;
  6.  
  7.  
  8. namespace RobvanderWoude
  9. {
  10. 	class CatchStrayWindows
  11. 	{
  12. 		static readonly string progver = "1.00";
  13.  
  14. 		static readonly int screenwidth = Screen.PrimaryScreen.WorkingArea.Width;
  15. 		static readonly int screenheight = Screen.PrimaryScreen.WorkingArea.Height;
  16.  
  17. 		static bool includeminimized = false;
  18. 		static bool includeanonymous = false;
  19.  
  20.  
  21. 		static int Main( string[] args )
  22. 		{
  23. 			// Set console encoding to UTF-8
  24. 			Console.OutputEncoding = System.Text.Encoding.UTF8;
  25.  
  26.  
  27. 			#region Parse Command Line
  28.  
  29. 			foreach ( string arg in args )
  30. 			{
  31. 				switch ( arg.ToUpper( ) )
  32. 				{
  33. 					case "/?":
  34. 						return ShowHelp( );
  35. 					case "/IA":
  36. 						if ( includeanonymous )
  37. 						{
  38. 							return ShowHelp( "Duplicate command line switch /IA" );
  39. 						}
  40. 						includeanonymous = true;
  41. 						break;
  42. 					case "/IM":
  43. 						if ( includeminimized )
  44. 						{
  45. 							return ShowHelp( "Duplicate command line switch /IM" );
  46. 						}
  47. 						includeminimized = true;
  48. 						break;
  49. 					default:
  50. 						return ShowHelp( "Invalid command line argument \"{0}\"", arg );
  51. 				}
  52. 			}
  53.  
  54. 			#endregion Parse Command Line
  55.  
  56.  
  57. 			// List active windows
  58. 			GetDesktopWindowHandlesAndTitles( out windows );
  59.  
  60.  
  61. 			#region Restore Minimized Windows
  62.  
  63. 			// First restore/maximize any minimized window(s) that should be included
  64. 			foreach ( IntPtr handle in windows.Keys )
  65. 			{
  66. 				if ( windows[handle] != "(no title)" || includeanonymous )
  67. 				{
  68. 					if ( !IsIconic( handle ) || includeminimized )
  69. 					{
  70. 						string debugmessage = string.Format( "Maximized \"{0}\"", windows[handle] );
  71. 						//string debugmessage = string.Format( "Restored \"{0}\"", windows[handle] );
  72. 						if ( IsIconic( handle ) && includeminimized )
  73. 						{
  74. 							Console.WriteLine( debugmessage );
  75. 							ShowWindow( handle, SW_SHOWMAXIMIZED );
  76. 							//ShowWindow( handle, SW_SHOWMAXIMIZED );
  77. 						}
  78. 					}
  79. 				}
  80. 			}
  81.  
  82. 			#endregion Restore Minimized Windows
  83.  
  84.  
  85. 			#region Move Windows to Primary Monitor
  86.  
  87. 			// Next move the window(s) to the primary monitor
  88. 			int count = 0;
  89.  
  90. 			foreach ( IntPtr handle in windows.Keys )
  91. 			{
  92. 				if ( windows[handle] != "(no title)" || includeanonymous )
  93. 				{
  94. 					if ( !IsIconic( handle ) || includeminimized )
  95. 					{
  96. 						RECT rect = new RECT( );
  97. 						if ( GetWindowRect( handle, ref rect ) )
  98. 						{
  99. 							if ( ( rect.Left > screenwidth || rect.Right < 20 || rect.Top > screenheight || rect.Bottom < 20 ) && ( rect.Left != 0 && rect.Top != 0 ) )
  100. 							{
  101. 								int width = rect.Right - rect.Left;
  102. 								int height = rect.Bottom - rect.Top;
  103. 								bool repaint = true;
  104. 								string debugmessage = string.Format( "Moved \"{0}\" from ({1},{2}) to ({3},{4})", windows[handle], rect.Left, rect.Top, 0, 0 );
  105. 								if ( MoveWindow( handle, 0, 0, width, height, repaint ) )
  106. 								{
  107. 									Console.WriteLine( debugmessage );
  108. 									count += 1;
  109. 								}
  110. 							}
  111. 						}
  112. 					}
  113. 				}
  114. 			}
  115.  
  116. 			#endregion Move Windows to Primary Monitor
  117.  
  118.  
  119. 			return count;
  120. 		}
  121.  
  122.  
  123.  
  124. 		#region Check If Minimized
  125.  
  126. 		[DllImport( "user32.dll" )]
  127. 		[return: MarshalAs( UnmanagedType.Bool )]
  128. 		static extern bool IsIconic( IntPtr hWnd ); // true if window is minimized
  129.  
  130. 		#endregion Check If Minimized
  131.  
  132.  
  133. 		#region Get Window Size
  134.  
  135. 		// Get window position and size
  136. 		// https://stackoverflow.com/a/1434577
  137. 		[DllImport( "user32.dll", SetLastError = true )]
  138. 		[return: MarshalAs( UnmanagedType.Bool )]
  139. 		static extern bool GetWindowRect( IntPtr hWnd, ref RECT lpRect );
  140. 		[StructLayout( LayoutKind.Sequential )]
  141.  
  142.  
  143. 		public struct RECT
  144. 		{
  145. 			public int Left;
  146. 			public int Top;
  147. 			public int Right;
  148. 			public int Bottom;
  149. 		}
  150.  
  151. 		#endregion Get Window Size
  152.  
  153.  
  154. 		#region List Desktop Windows
  155.  
  156. 		// Based on code by Rod Stephens
  157. 		// List desktop windows in C#
  158. 		// http://csharphelper.com/blog/2016/08/list-desktop-windows-in-c/
  159.  
  160. 		[DllImport( "user32.dll" )]
  161. 		[return: MarshalAs( UnmanagedType.Bool )]
  162. 		private static extern bool IsWindowVisible( IntPtr hWnd );
  163.  
  164. 		[DllImport( "user32.dll", EntryPoint = "GetWindowText",
  165. 		ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true )]
  166. 		private static extern int GetWindowText( IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount );
  167.  
  168. 		[DllImport( "user32.dll", EntryPoint = "EnumDesktopWindows",
  169. 		ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true )]
  170. 		private static extern bool EnumDesktopWindows( IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam );
  171.  
  172. 		// Define the callback delegate's type.
  173. 		private delegate bool EnumDelegate( IntPtr hWnd, int lParam );
  174.  
  175. 		// Save window titles and handles in Dictionary
  176. 		private static Dictionary<IntPtr, string> windows;
  177.  
  178. 		// Return a list of the desktop windows' handles and titles.
  179. 		public static void GetDesktopWindowHandlesAndTitles( out Dictionary<IntPtr, string> windowslist )
  180. 		{
  181. 			windowslist = new Dictionary<IntPtr, string>( );
  182.  
  183. 			if ( !EnumDesktopWindows( IntPtr.Zero, FilterCallback, IntPtr.Zero ) )
  184. 			{
  185. 				windowslist = null;
  186. 			}
  187. 			else
  188. 			{
  189. 				windowslist = windows;
  190. 			}
  191. 		}
  192.  
  193.  
  194. 		// We use this function to filter windows
  195. 		// This version selects visible windows that aren't minimized
  196. 		private static bool FilterCallback( IntPtr hWnd, int lParam )
  197. 		{
  198. 			// Get the window's title
  199. 			StringBuilder sb_title = new StringBuilder( 1024 );
  200. 			int _ = GetWindowText( hWnd, sb_title, sb_title.Capacity );
  201. 			string title = sb_title.ToString( );
  202.  
  203. 			// If the window is visible and has a title, save it.
  204. 			if ( IsWindowVisible( hWnd ) )
  205. 			{
  206. 				if ( string.IsNullOrEmpty( title ) )
  207. 				{
  208. 					title = "(no title)";
  209. 				}
  210. 				windows.Add( hWnd, title );
  211. 			}
  212.  
  213. 			// Return true to indicate that we should continue enumerating windows
  214. 			return true;
  215. 		}
  216.  
  217. 		#endregion List Desktop Windows
  218.  
  219.  
  220. 		#region Move Window
  221.  
  222. 		// Based on code by Roberto Luis Bisb\u00E9
  223. 		// Moving windows programatically with Windows API, the path to WinResize
  224. 		// https://rlbisbe.net/2013/11/19/moving-windows-programatically-with-windows-api-the-path-to-winresize/
  225.  
  226. 		[DllImport( "user32.dll" )]
  227. 		public static extern bool MoveWindow( IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint );
  228.  
  229. 		#endregion Move Window
  230.  
  231.  
  232. 		#region Restore Window
  233.  
  234. 		// private const int SW_SHOWNORMAL = 1;
  235. 		// private const int SW_SHOWMINIMIZED = 2;
  236. 		private const int SW_SHOWMAXIMIZED = 3;
  237.  
  238.  
  239. 		[DllImport( "user32.dll" )]
  240. 		private static extern bool ShowWindow( IntPtr hWnd, int nCmdShow );
  241.  
  242.  
  243. 		[DllImport( "user32.dll" )]
  244. 		private static extern bool ShowWindowAsync( IntPtr hWnd, int nCmdShow );
  245.  
  246. 		#endregion Restore Window
  247.  
  248.  
  249. 		#region Error handling
  250.  
  251. 		public static int ShowHelp( params string[] errmsg )
  252. 		{
  253. 			#region Error Message
  254.  
  255. 			if ( errmsg.Length > 0 )
  256. 			{
  257. 				List<string> errargs = new List<string>( errmsg );
  258. 				errargs.RemoveAt( 0 );
  259. 				Console.Error.WriteLine( );
  260. 				Console.ForegroundColor = ConsoleColor.Red;
  261. 				Console.Error.Write( "ERROR:\t" );
  262. 				Console.ForegroundColor = ConsoleColor.White;
  263. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  264. 				Console.ResetColor( );
  265. 			}
  266.  
  267. 			#endregion Error Message
  268.  
  269.  
  270. 			#region Help Text
  271.  
  272. 			/*
  273. 			CatchStrayWindows.exe,  Version 1.00
  274. 			Move out-of-sight windows back to the primary screen
  275.  
  276. 			Usage:   CatchStrayWindows  [ /IA ]  [ /IM ]
  277.  
  278. 			Options: /IA	Include Anonymous windows, i.e. those without title
  279. 			         /IM    Include Minimized windows
  280.  
  281. 			Credits: Get window position and size
  282. 			         https://stackoverflow.com/a/1434577
  283. 			         List desktop windows based on code by Rod Stephens
  284. 			         http://csharphelper.com/blog/2016/08/list-desktop-windows-in-c/
  285. 			         Moving windows based on code by Roberto Luis Bisb\u00E9
  286. 			         https://rlbisbe.net/2013/11/19/
  287. 			         moving-windows-programatically-with-windows-api-the-path-to-winresize/
  288.  
  289. 			Note:    Return code equals number of moved windows, or -1 in case of errors.
  290.  
  291. 			Written by Rob van der Woude
  292. 			https://www.robvanderwoude.com
  293. 			*/
  294.  
  295. 			#endregion Help Text
  296.  
  297.  
  298. 			#region Display Help Text
  299.  
  300. 			Console.Error.WriteLine( );
  301.  
  302. 			Console.Error.WriteLine( "CatchStrayWindows.exe,  Version {0}", progver );
  303.  
  304. 			Console.Error.WriteLine( "Move out-of-sight windows back to the primary screen" );
  305.  
  306. 			Console.Error.WriteLine( );
  307.  
  308. 			Console.Error.Write( "Options: " );
  309. 			Console.ForegroundColor = ConsoleColor.White;
  310. 			Console.Error.Write( "/IA    I" );
  311. 			Console.ResetColor( );
  312. 			Console.Error.Write( "nclude " );
  313. 			Console.ForegroundColor = ConsoleColor.White;
  314. 			Console.Error.Write( "A" );
  315. 			Console.ResetColor( );
  316. 			Console.Error.WriteLine( "nonymous windows, i.e. those without title" );
  317.  
  318. 			Console.ForegroundColor = ConsoleColor.White;
  319. 			Console.Error.Write( "         /IM    I" );
  320. 			Console.ResetColor( );
  321. 			Console.Error.Write( "nclude " );
  322. 			Console.ForegroundColor = ConsoleColor.White;
  323. 			Console.Error.Write( "M" );
  324. 			Console.ResetColor( );
  325. 			Console.Error.WriteLine( "inimized windows" );
  326.  
  327. 			Console.Error.WriteLine( );
  328.  
  329. 			Console.Error.WriteLine( "Credits: Get window position and size" );
  330.  
  331. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  332. 			Console.Error.WriteLine( "         https://stackoverflow.com/a/1434577" );
  333. 			Console.ResetColor( );
  334.  
  335. 			Console.Error.WriteLine( "         List desktop windows based on code by Rod Stephens" );
  336.  
  337. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  338. 			Console.Error.WriteLine( "         http://csharphelper.com/blog/2016/08/list-desktop-windows-in-c/" );
  339. 			Console.ResetColor( );
  340.  
  341. 			Console.Error.WriteLine( "         Moving windows based on code by Roberto Luis Bisb\u00E9" );
  342.  
  343. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  344. 			Console.Error.WriteLine( "         https://rlbisbe.net/2013/11/19/" );
  345. 			Console.Error.WriteLine( "         moving-windows-programatically-with-windows-api-the-path-to-winresize/" );
  346. 			Console.ResetColor( );
  347.  
  348. 			Console.Error.WriteLine( );
  349.  
  350. 			Console.Error.WriteLine( "Note:    Return code equals number of moved windows, or -1 in case of errors." );
  351.  
  352. 			Console.Error.WriteLine( );
  353.  
  354. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  355.  
  356. 			Console.Error.WriteLine( "https://www.robvanderwoude.com" );
  357.  
  358. 			#endregion Display Help Text
  359.  
  360. 			return -1;
  361. 		}
  362.  
  363. 		#endregion Error handling
  364. 	}
  365. }
  366.  

page last modified: 2024-04-16; loaded in 0.0132 seconds