using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; namespace RobvanderWoude { class ActivateWindow { static readonly string progver = "1.03"; static bool debug = false; static bool exactmatch = false; static List windowtitles = new List( ); static string exact = "partial "; static string matchingtitle = string.Empty; static string progname = string.Empty; static string windowtitle = string.Empty; static int Main( string[] args ) { bool querycurrent = false; bool useprogname = false; #region Parse and Validate Command Line if ( args.Length == 0 ) { return ShowHelp( ); } foreach ( string arg in args ) { if ( arg[0] == '/' ) { switch ( arg.ToUpper( ) ) { case "/?": return ShowHelp( ); case "/C": if ( querycurrent ) { return ShowHelp( "Duplicate switch /C" ); } querycurrent = true; break; case "/D": if ( useprogname ) { return ShowHelp( "Switches /P and /D are mutually exclusive" ); } if ( debug ) { return ShowHelp( "Duplicate switch /D" ); } debug = true; break; case "/P": if ( debug ) { return ShowHelp( "Switches /P and /D are mutually exclusive" ); } if ( useprogname ) { return ShowHelp( "Duplicate switch /P" ); } useprogname = true; break; case "/X": if ( exactmatch ) { return ShowHelp( "Duplicate switch /X" ); } exactmatch = true; exact = "exact "; break; default: return ShowHelp( "Invalid switch \"{0}\"", arg ); } } else { if ( !windowtitles.Contains( arg ) ) { windowtitles.Add( arg ); } } } if ( useprogname ) { if ( exactmatch ) { return ShowHelp( "Switches /P and /X are mutually exclusive" ); } if ( windowtitles.Count == 1 ) { progname = windowtitles[0]; } else { return ShowHelp( "Specifie a single program executable when using /P switch" ); } } if ( querycurrent && args.Length > 1 ) { return ShowHelp( "/C switch cannot be combined with other command line arguments" ); } #if DEBUG debug = true; #endif #endregion Parse and validate Command Line if ( querycurrent ) { return QueryActive( ); } else if ( useprogname ) { return ActivateByProgName( ); } else { return ActivateByTitle( ); } } static int ActivateByProgName( ) { // Based on code by Hans Passant on StackOverflow.com // https://stackoverflow.com/a/2819747 Process[] proc = Process.GetProcessesByName( progname ); // progname should be WITHOUT extension if ( proc.Length > 0 ) { SetForegroundWindow( proc[0].MainWindowHandle ); // Make first match the foreground window } else { proc = Process.GetProcessesByName( Path.GetFileNameWithoutExtension( progname ) ); // try stripping extension if ( proc.Length > 0 ) { SetForegroundWindow( proc[0].MainWindowHandle ); // Make first match the foreground window } else { Console.Error.WriteLine( "No process with specified name \"{0}\" was found.", progname ); return 1; } } return 0; } static int ActivateByTitle( ) { // Find the window with the specified title IntPtr handle = FindWindow( windowtitles, exactmatch ); if ( handle == IntPtr.Zero ) { Console.Error.WriteLine( "No window was found with {0}title.", exact ); return 1; } else { if ( debug && !exactmatch ) { Console.WriteLine( "Specified title : \"{0}\"\nMatching title : \"{1}\"\n", windowtitle, matchingtitle ); } // If found, make it the foreground window if ( !SetForegroundWindow( handle ) ) { Console.Error.WriteLine( "Unable to move the specified window to the foreground." ); return -1; } } return 0; } static IntPtr FindWindow( List titles, bool exacttitlematch = false ) { foreach ( Process process in Process.GetProcesses( ) ) { foreach( string title in titles ) { if ( process.MainWindowTitle.Equals( title, StringComparison.InvariantCultureIgnoreCase ) ) { return process.MainWindowHandle; // Return the FIRST matching window } else if ( !exacttitlematch ) { if ( process.MainWindowTitle.ToUpper( ).Contains( title.ToUpper( ) ) ) { matchingtitle = process.MainWindowTitle; windowtitle = title; return process.MainWindowHandle; // Return the FIRST matching window } } } } return IntPtr.Zero; // In case no matching title was found } static string GetActiveWindowTitle( ) { // Code by Jorge Ferreira on StackOverflow.com // https://stackoverflow.com/a/115905 const int nChars = 256; StringBuilder Buff = new StringBuilder( nChars ); IntPtr handle = GetForegroundWindow( ); if ( GetWindowText( handle, Buff, nChars ) > 0 ) { return Buff.ToString( ); } return null; } static int QueryActive( ) { // Find the title of the currently active window string activewindowtitle = GetActiveWindowTitle( ); if ( string.IsNullOrWhiteSpace( activewindowtitle ) ) { Console.Error.WriteLine( "Unable to query the active window's title." ); return -1; } else { Console.WriteLine( activewindowtitle ); return 0; } } #region DLL Imports [DllImport( "user32.dll" )] [return: MarshalAs( UnmanagedType.Bool )] static extern bool SetForegroundWindow( IntPtr hWnd ); [DllImport( "user32.dll" )] static extern IntPtr GetForegroundWindow( ); [DllImport( "user32.dll" )] static extern int GetWindowText( IntPtr hWnd, StringBuilder text, int count ); #endregion DLL Imports #region Error handling static int ShowHelp( params string[] errmsg ) { #region Error Message if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } #endregion Error Message #region Help Text /* ActivateWindow.exe, Version 1.03 Activate the specified window Usage: ActivateWindow.exe title [ title [ title ... ] ] [ /D ] [ /X ] or: ActivateWindow.exe progname /P or: ActivateWindow.exe /C Where: title is a (partial) title of the window to be activated (first matching title is used) progname is the executable name of the window to be activated (name only, no extension) Options: /C show Currently active window's title on screen /D Debug mode: show match used for partial title /P specified name is Program executable name (default: specified name is window title) /X window title and specified title must match eXactly (default: window title contains specified title) Notes: With /P switch, if no match is found, the program will try and strip an extension from progname if applicable, and search again. Return code 0 on success, 1 if no match, or -1 in case of errors. Written by Rob van der Woude https://www.robvanderwoude.com */ #endregion Help Text #region Display Help Text Console.Error.WriteLine( ); Console.Error.WriteLine( "ActivateWindow.exe, Version {0}", progver ); Console.Error.WriteLine( "Activate the specified window" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "ActivateWindow.exe title [ title [ title ... ] ] [ /D ] [ /X ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( " or: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "ActivateWindow.exe progname /P" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( " or: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "ActivateWindow.exe /C" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Write( "title " ); Console.ResetColor( ); Console.WriteLine( "is a (partial) title of the window to be activated" ); Console.Error.WriteLine( " (first matching title is used)" ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " progname " ); Console.ResetColor( ); Console.Error.Write( "is the executable " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "name" ); Console.ResetColor( ); Console.Error.WriteLine( " of the window to be activated" ); Console.Error.WriteLine( " (name only, no extension)" ); Console.Error.WriteLine( ); Console.Error.Write( "Options: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/C " ); Console.ResetColor( ); Console.Error.Write( "show " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "C" ); Console.ResetColor( ); Console.Error.WriteLine( "urrently active window's title on screen" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /D D" ); Console.ResetColor( ); Console.Error.WriteLine( "ebug mode: show match used for partial title" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /P" ); Console.ResetColor( ); Console.Error.Write( " specified name is " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "P" ); Console.ResetColor( ); Console.Error.WriteLine( "rogram executable name" ); Console.Error.WriteLine( " (default: specified name is window title)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /X " ); Console.ResetColor( ); Console.Error.Write( "window title and specified title must match e" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "X" ); Console.ResetColor( ); Console.Error.WriteLine( "actly" ); Console.Error.Write( " (default: window title " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "contains " ); Console.ResetColor( ); Console.Error.WriteLine( "specified title)" ); Console.Error.WriteLine( ); Console.Error.Write( "Notes: With " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/P" ); Console.ResetColor( ); Console.Error.WriteLine( " switch, if no match is found, the program will try and" ); Console.Error.Write( " strip an extension from " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "progname" ); Console.ResetColor( ); Console.Error.WriteLine( " if applicable, and search again." ); Console.Error.WriteLine( " Return code 0 on success, 1 if no match, or -1 in case of errors." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "https://www.robvanderwoude.com" ); #endregion Display Help Text return -1; } #endregion Error handling } }