using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; namespace Yaulw.Process { /// /// Used to Manage Launching/Killing Processes In an Application /// public static class PStarter { #region Private Static Members private static Dictionary _StartedProcesses = new Dictionary(); #endregion #region Public Process Starter Methods /// /// Use this to call a DosCommand in a hidden command prompt and have the command return /// you a value back, read from standard output /// /// processStartInfo /// true to wait till process ends, false otherwise /// the PID of the the newly started Process, or 0 if an error occured public static string RunDosCommand(string DosCommand) { ProcessStartInfo processStart = PStartInfo.CreateCMDDosCommandProcess(DosCommand, true); processStart.RedirectStandardOutput = true; string output = String.Empty; if ((processStart != null) && System.IO.File.Exists(processStart.FileName)) { // Start the Process try { System.Diagnostics.Process p1; p1 = System.Diagnostics.Process.Start(processStart); output = p1.StandardOutput.ReadToEnd(); p1.WaitForExit(); if (String.IsNullOrEmpty(output)) output = p1.StandardOutput.ReadToEnd(); } catch (Exception e) { string msg = e.Message; /* ignore */ } } return output; } /// /// Always Starts a New Process /// /// processStartInfo /// true to wait till process ends, false otherwise /// true to check if the process of the same name has already been started, false otherwise /// the PID of the the newly started Process, or 0 if an error occured //public static uint StartProcess(ProcessStartInfo processStart, bool bWait = false, bool bMustBeUnique = false) public static uint StartProcess(ProcessStartInfo processStart, bool bWait, bool bMustBeUnique) { if ((processStart != null) && System.IO.File.Exists(processStart.FileName)) { // Enforce Uniqueness * DISABLED * We can't ENFORCE UNIQUENESS WITHOUT ALSO INCLUDING COMMAND-LINE PARAMETERS // ~TO DO SOMETIME LATER * DOESN"T MATTER HERE * ALREADY HANDLED BY CALLER ANYWAY * //if (bMustBeUnique && ContainsProcessExe(processStart.FileName)) //{ // return 0; //} //else if (bMustBeUnique) //{ // // Iterate the system's Processes's and make sure that the same process doesn't exist // System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(Path.GetFileNameWithoutExtension(processStart.FileName)); // foreach (System.Diagnostics.Process process in processes) // { // // Found, return 0 // if (String.Compare(process.MainModule.FileName, processStart.FileName, true) == 0) // return 0; // } //} // Start the Process try { System.Diagnostics.Process p1; p1 = System.Diagnostics.Process.Start(processStart); // DISABLED // Map if for later use //_StartedProcesses.Add((uint)p1.Id, processStart.FileName.ToLower()); // Wait if asked if (bWait) p1.WaitForExit(); return (uint)p1.Id; } catch (Exception) { /* ignore */ } } return 0; } /// /// Kills any process started thru PStarter, if it matches the Passed in PID /// /// The Pid of the Process to Stop /// true to only shutdown a process that was started by PStarted /// The time in Seconds to wait after closing the Process /// true to try sending WM_CLOSE message to Window prior Killing Process /// The time in Seconds to wait after sending WM_CLOSE message for Process to Close * Only takes effect if bTryClosingMainWindowFirst is true * /// true if process stopped, false otherwise //public static bool KillProcess(uint PID, bool bMustBeHaveBeenStartedByUs = false, uint CloseWaitTimeInSeconds = 1, bool bTryClosingMainWindowFirst = true, uint MainWindowCloseWaitTimeInSeconds = 2) public static bool KillProcess(uint PID, bool bMustBeHaveBeenStartedByUs, uint CloseWaitTimeInSeconds, bool bTryClosingMainWindowFirst, uint MainWindowCloseWaitTimeInSeconds) { // Valid Process Id bool bValidToClose = (PID != 0); // Make sure that PStarted Started This Process if (bValidToClose && bMustBeHaveBeenStartedByUs) bValidToClose = _StartedProcesses.ContainsKey(PID); // Is this process valid to close? if (bValidToClose) { System.Diagnostics.Process p1 = null; // Try getting the Process try { p1 = System.Diagnostics.Process.GetProcessById((int)PID); } catch (Exception) {/* ignore */} // Process Found if (p1 != null) { // If Main Window Exists, Try Closing this first if (bTryClosingMainWindowFirst) { IntPtr hWnd = p1.MainWindowHandle; if (hWnd == IntPtr.Zero) { // Try getting the window handle by Iterating TopLevel Windows hWnd = Win32.Functions.GetFirstTopLevelWindowForProcess((int)PID); } // If we have a valid Window Handle, try closing it nicely if (hWnd != IntPtr.Zero && Win32.User32.IsWindow(hWnd)) { // Try the new school way && the old school way !!! p1.CloseMainWindow(); Win32.User32.PostMessage(hWnd, (int)Win32.Definitions.WM.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); // Wait a little.. as specified by the configuration System.Threading.Thread.Sleep((int)TimeSpan.FromSeconds(MainWindowCloseWaitTimeInSeconds).TotalMilliseconds); // Retry getting the Process *Should be closed by now* try { p1 = null; p1 = System.Diagnostics.Process.GetProcessById((int)PID); } catch (Exception) {/* ignore */} } } // Last Resort, Always try to Kill the Process try { if (p1 != null) p1.Kill(); } catch (Exception) { /* ignore */ } // Wait a little System.Threading.Thread.Sleep((int)TimeSpan.FromSeconds(CloseWaitTimeInSeconds).TotalMilliseconds); // Retry getting the Process *Must be closed by now* try { p1 = null; p1 = System.Diagnostics.Process.GetProcessById((int)PID); } catch (Exception) {/* ignore */} if (p1 == null) { // DISABLED //_StartedProcesses.Remove(PID); return true; } } } return false; } #endregion #region Public Process Starter Helper Methods /// /// Retrieves the PIDs that were started using PStarter /// /// an uint[] array with Pids, or an empty array if none found public static uint[] AllStartedProcessIDs() { // DISABLED //List Pids = new List(); //foreach (int key in _StartedProcesses.Keys) // Pids.Add((uint)key); //return Pids.ToArray(); return null; } /// /// Since when we start a Process and it can die/killed externally we wouldn't know, /// PIDs #'s could be re-used by the OS, so we could accidentially kill a Process that isn't our own. /// This functions allows a monitoring program to call in with currently running PIDs they know are good /// on the running system, we can use these numbers and discard any PIDs internally that are no longer accurate /// * This function will DELETE PIDs/Keys internally * call it only with is a complete list of all PIDs. /// /// an uint[] array with currently Running PIDs, that we can compare to our started PIDs public static void PerformGeneralCleanupOfAllStartedProcessIDs(uint[] currentlyRunningPIDs) { // DISABLED //if ((currentlyRunningPIDs != null) && (currentlyRunningPIDs.Length > 0)) //{ // // Iterate thru the Internal DS and track any PID Keys that are no longer valid // List RunningPidKeysToRemove = new List(); // foreach (uint key in _StartedProcesses.Keys) // { // if (!currentlyRunningPIDs.Contains(key)) // RunningPidKeysToRemove.Add(key); // } // // Remove * no longer valid * PID / Keys // foreach (uint keyToRemove in RunningPidKeysToRemove) // _StartedProcesses.Remove(keyToRemove); //} } /// /// Returns true if the ProcessExe was started with PStarter, False otherwise /// /// Process Executable Filename and Path /// true, if found, false otherwise public static bool ContainsProcessExe(string FileName) { return _StartedProcesses.ContainsValue(FileName.ToLower()); } /// /// Get's the first PID that matches the Given Exe Process FileName /// /// Process Executable Filename and Path /// a Valid PID or 0 if not found public static uint GetFirstPIDForProcessExe(string FileName) { if (ContainsProcessExe(FileName)) { foreach (uint key in _StartedProcesses.Keys) { if (String.Compare(_StartedProcesses[key], FileName, true) == 0) return key; } } return 0; } /// /// Get's all the PIDs that matches the Given Exe Process FileName /// /// Process Executable Filename and Path /// valid PIDs or empty PID array, if not found public static uint[] GetPIDsForProcessExe(string FileName) { List foundProcess = new List(); if (ContainsProcessExe(FileName)) { foreach (uint key in _StartedProcesses.Keys) { if (String.Compare(_StartedProcesses[key], FileName, true) == 0) foundProcess.Add(key); } } return foundProcess.ToArray(); } #endregion } }