initial checkin of yaulw (locally)
This commit is contained in:
110
Process/PStartInfo.cs
Normal file
110
Process/PStartInfo.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Yaulw.Tools;
|
||||
|
||||
namespace Yaulw.Process
|
||||
{
|
||||
/// <remarks>
|
||||
/// Helper Class to create ProcessStartInfo Objects
|
||||
/// </remarks>
|
||||
public static class PStartInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a simple ProcessStartInfo Object
|
||||
/// </summary>
|
||||
/// <param name="ExeFileNPath">Exe File and Path to execute</param>
|
||||
/// <param name="CmdLine">CmdLine Params to process, optional</param>
|
||||
/// <param name="bUseRunAs">If true, will set "RunAs" For the Process, to Run as Administrator</param>
|
||||
/// <param name="WindowStyle">the windows style to initialize main window with</param>
|
||||
/// <param name="bUseShellExecute">True to use Explorer.exe shellexecute, false otherise</param>
|
||||
/// <returns>a ProcessStartInfo Object or null if error occured</returns>
|
||||
public static ProcessStartInfo CreateProcess(string ExeFileNPath, string CmdLine = "", string WorkingDir = "", bool bUseRunAs = false, ProcessWindowStyle WindowStyle = ProcessWindowStyle.Normal, bool bUseShellExecute = true)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(ExeFileNPath) && System.IO.File.Exists(ExeFileNPath))
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo(ExeFileNPath, CmdLine);
|
||||
startInfo.WindowStyle = WindowStyle;
|
||||
startInfo.UseShellExecute = bUseShellExecute;
|
||||
if (bUseRunAs)
|
||||
startInfo.Verb = "runas";
|
||||
|
||||
// Set up Working Directory, if one is found
|
||||
if(!String.IsNullOrEmpty(WorkingDir))
|
||||
startInfo.WorkingDirectory = PathNaming.PathEndsWithSlash(WorkingDir);
|
||||
else
|
||||
startInfo.WorkingDirectory = Path.GetDirectoryName(ExeFileNPath);
|
||||
return startInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an url ProcessStartInfo Object
|
||||
/// </summary>
|
||||
/// <param name="url">url to launche</param>
|
||||
/// <returns>a ProcessStartInfo Object or null if error occured</returns>
|
||||
public static ProcessStartInfo LaunchUrl(string url)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(url))
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo(url);
|
||||
startInfo.UseShellExecute = true;
|
||||
return startInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CMD.Exe CommandLine Executable ProcessStartInfo Object
|
||||
/// </summary>
|
||||
/// <param name="scriptFileNPath">Full FileName and Path to script file to execute via CMD.exe</param>
|
||||
/// <param name="bUseRunAs">If true, will set "RunAs" For the Process, to Run as Administrator</param>
|
||||
/// <returns>a ProcessStartInfo Object or null if error occured</returns>
|
||||
public static ProcessStartInfo CreateCMDScriptProcess(string scriptFileNPath, bool bUseRunAs = false)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(scriptFileNPath) && System.IO.File.Exists(scriptFileNPath))
|
||||
{
|
||||
//The "/C" Tells Windows to Run The Command then Terminate
|
||||
string strCmdLine = "/C " + '\"' + scriptFileNPath + '\"';
|
||||
string WindowsSystem32Folder = System.Environment.GetFolderPath(Environment.SpecialFolder.System);
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo((WindowsSystem32Folder + "\\" + "CMD.exe"), strCmdLine);
|
||||
//startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
|
||||
startInfo.CreateNoWindow = true;
|
||||
startInfo.UseShellExecute = false;
|
||||
if (bUseRunAs)
|
||||
startInfo.Verb = "runas";
|
||||
startInfo.WorkingDirectory = Path.GetDirectoryName(scriptFileNPath);
|
||||
return startInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CMD.Exe CommandLine Executable ProcessStartInfo Object
|
||||
/// </summary>
|
||||
/// <param name="DosCommand">Dos Command to Execute</param>
|
||||
/// <param name="bUseRunAs">If true, will set "RunAs" For the Process, to Run as Administrator</param>
|
||||
/// <returns>a ProcessStartInfo Object or null if error occured</returns>
|
||||
public static ProcessStartInfo CreateCMDDosCommandProcess(string DosCommand, bool bUseRunAs = false)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(DosCommand))
|
||||
{
|
||||
//The "/C" Tells Windows to Run The Command then Terminate
|
||||
string strCmdLine = "/C " + '\"' + DosCommand + '\"';
|
||||
string WindowsSystem32Folder = System.Environment.GetFolderPath(Environment.SpecialFolder.System);
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo((WindowsSystem32Folder + "\\" + "CMD.exe"), strCmdLine);
|
||||
//startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
|
||||
startInfo.CreateNoWindow = true;
|
||||
startInfo.UseShellExecute = false;
|
||||
if (bUseRunAs)
|
||||
startInfo.Verb = "runas";
|
||||
return startInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
274
Process/PStarter.cs
Normal file
274
Process/PStarter.cs
Normal file
@@ -0,0 +1,274 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Yaulw.Process
|
||||
{
|
||||
/// <remarks>
|
||||
/// Used to Manage Launching/Killing Processes In an Application
|
||||
/// </remarks>
|
||||
public static class PStarter
|
||||
{
|
||||
#region Private Static Members
|
||||
private static Dictionary<uint, String> _StartedProcesses = new Dictionary<uint, String>();
|
||||
#endregion
|
||||
|
||||
#region Public Process Starter Methods
|
||||
|
||||
/// <summary>
|
||||
/// Use this to call a DosCommand in a hidden command prompt and have the command return
|
||||
/// you a value back, read from standard output
|
||||
/// </summary>
|
||||
/// <param name="processStart">processStartInfo</param>
|
||||
/// <param name="bWait">true to wait till process ends, false otherwise</param>
|
||||
/// <returns>the PID of the the newly started Process, or 0 if an error occured</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Always Starts a New Process
|
||||
/// </summary>
|
||||
/// <param name="processStart">processStartInfo</param>
|
||||
/// <param name="bWait">true to wait till process ends, false otherwise</param>
|
||||
/// <param name="bMustBeUnique">true to check if the process of the same name has already been started, false otherwise</param>
|
||||
/// <returns>the PID of the the newly started Process, or 0 if an error occured</returns>
|
||||
//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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kills any process started thru PStarter, if it matches the Passed in PID
|
||||
/// </summary>
|
||||
/// <param name="PID">The Pid of the Process to Stop</param>
|
||||
/// <param name="bMustBeHaveBeenStartedByUs">true to only shutdown a process that was started by PStarted</param>
|
||||
/// <param name="CloseWaitTimeInSeconds">The time in Seconds to wait after closing the Process</param>
|
||||
/// <param name="bTryClosingMainWindowFirst">true to try sending WM_CLOSE message to Window prior Killing Process</param>
|
||||
/// <param name="MainWindowCloseWaitTimeInSeconds">The time in Seconds to wait after sending WM_CLOSE message for Process to Close * Only takes effect if bTryClosingMainWindowFirst is true *</param>
|
||||
/// <returns>true if process stopped, false otherwise</returns>
|
||||
//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
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the PIDs that were started using PStarter
|
||||
/// </summary>
|
||||
/// <returns>an uint[] array with Pids, or an empty array if none found</returns>
|
||||
public static uint[] AllStartedProcessIDs()
|
||||
{
|
||||
// DISABLED
|
||||
//List<uint> Pids = new List<uint>();
|
||||
//foreach (int key in _StartedProcesses.Keys)
|
||||
// Pids.Add((uint)key);
|
||||
//return Pids.ToArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="currentlyRunningPIDs">an uint[] array with currently Running PIDs, that we can compare to our started PIDs</param>
|
||||
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<uint> RunningPidKeysToRemove = new List<uint>();
|
||||
// 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);
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the ProcessExe was started with PStarter, False otherwise
|
||||
/// </summary>
|
||||
/// <param name="FileName">Process Executable Filename and Path</param>
|
||||
/// <returns>true, if found, false otherwise</returns>
|
||||
public static bool ContainsProcessExe(string FileName)
|
||||
{
|
||||
return _StartedProcesses.ContainsValue(FileName.ToLower());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get's the first PID that matches the Given Exe Process FileName
|
||||
/// </summary>
|
||||
/// <param name="FileName">Process Executable Filename and Path</param>
|
||||
/// <returns>a Valid PID or 0 if not found</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get's all the PIDs that matches the Given Exe Process FileName
|
||||
/// </summary>
|
||||
/// <param name="FileName">Process Executable Filename and Path</param>
|
||||
/// <returns>valid PIDs or empty PID array, if not found</returns>
|
||||
public static uint[] GetPIDsForProcessExe(string FileName)
|
||||
{
|
||||
List<uint> foundProcess = new List<uint>();
|
||||
if (ContainsProcessExe(FileName))
|
||||
{
|
||||
foreach (uint key in _StartedProcesses.Keys)
|
||||
{
|
||||
if (String.Compare(_StartedProcesses[key], FileName, true) == 0)
|
||||
foundProcess.Add(key);
|
||||
}
|
||||
}
|
||||
return foundProcess.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
309
Process/ProcessW.cs
Normal file
309
Process/ProcessW.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Diag = System.Diagnostics;
|
||||
using System.Management;
|
||||
|
||||
namespace Yaulw.Process
|
||||
{
|
||||
/// <remarks>
|
||||
/// Wrapper Class around System.Diagnostics's Process Class.
|
||||
/// Helper functions to make sure that we can safely interact with Processes.
|
||||
/// </remarks>
|
||||
public static class ProcessW
|
||||
{
|
||||
#region Process Caching
|
||||
|
||||
/// <summary>
|
||||
/// Process PID Lookup Cache - so that we can cache PIDs, we don't make a new system call
|
||||
/// Use this Property to Cache Process PIDs Lookups
|
||||
/// </summary>
|
||||
public static List<uint> ProcessPidsRunningCache { get { return s_RunningProcessesPids; } }
|
||||
private static List<uint> s_RunningProcessesPids = new List<uint>();
|
||||
|
||||
/// <summary>
|
||||
/// Process Obj Lookup Cache - so that for processes with the same name, we don't make a new system call
|
||||
/// Use this Property to Cache Process Obj Lookups
|
||||
/// </summary>
|
||||
public static Dictionary<string, List<Diag.Process>> ProcessObjsGetterCache { get { return s_processGetterCache; } }
|
||||
private static Dictionary<string, List<Diag.Process>> s_processGetterCache = new Dictionary<string, List<Diag.Process>>();
|
||||
|
||||
/// <summary>
|
||||
/// Clears the Process Obj Lookup Cache - Used in conjuction with AllRunningProcessesOf()
|
||||
/// </summary>
|
||||
public static void ClearProcessObjsGetterCache() { s_processGetterCache.Clear(); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Query For Processes
|
||||
|
||||
/// <summary>
|
||||
/// Safe GetProcessById Function, to make sure that it returns a valid Process Object
|
||||
/// </summary>
|
||||
/// <param name="PID">the PID to get the Process Object for</param>
|
||||
/// <param name="p">a valid Process obj, or null</param>
|
||||
/// <returns>true if successful, false otherwise</returns>
|
||||
public static bool GetProcessById(int PID, out Diag.Process p)
|
||||
{
|
||||
p = null;
|
||||
try
|
||||
{
|
||||
p = Diag.Process.GetProcessById(PID);
|
||||
return (p != null);
|
||||
}
|
||||
catch (Exception) { /*ignore */ }
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quick Check to see if other Process of that Name Are running
|
||||
/// </summary>
|
||||
/// <param name="ProcessName">name of process</param>
|
||||
/// <param name="bIgnoreVSHost">set to true to ignore Visual Studio's host .exe (debugger process)</param>
|
||||
/// <returns>true, if only one Process of that Name is running, false otherwise</returns>
|
||||
public static bool IsTheOnlyProcessRunning(string ProcessName, bool bIgnoreVSHost = true)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ProcessName))
|
||||
{
|
||||
// Visual Studio could be running this...
|
||||
int nLength1 = Diag.Process.GetProcessesByName(ProcessName).Length;
|
||||
int nLength2 = (bIgnoreVSHost)? 0 : Diag.Process.GetProcessesByName(ProcessName + ".vshost").Length;
|
||||
int nProcessCount = nLength1 + nLength2;
|
||||
return (nProcessCount == 0 || nProcessCount == 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this to quickly retrieve all Running PID on this machine
|
||||
/// * Excellent performance 10 MS *
|
||||
/// </summary>
|
||||
/// <returns>returns all running Pids</returns>
|
||||
public static List<uint> AllRunningPids()
|
||||
{
|
||||
Diag.Process[] processes = Diag.Process.GetProcesses();
|
||||
List<uint> allRunningPids = new List<uint>();
|
||||
if (allRunningPids != null)
|
||||
{
|
||||
foreach (Diag.Process p in processes)
|
||||
allRunningPids.Add((uint)p.Id);
|
||||
}
|
||||
return allRunningPids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all Processes of that ProcessName
|
||||
/// </summary>
|
||||
/// <param name="ProcessName">name of process</param>
|
||||
/// <param name="bUseLookupCache">If true, for .exe's in the Cache will return immediatly without a system call. Use ClearProcessObjsGetterCache() to clear Cache.</param>
|
||||
/// <param name="bIgnoreVSHost">set to true to ignore Visual Studio's host .exe (debugger process)</param>
|
||||
/// <returns>Returns all processes that match the process name, or empty array, if none found</returns>
|
||||
public static Diag.Process[] AllRunningProcessesOf(string ProcessName, bool bUseLookupCache = false, bool bIgnoreVSHost = true)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ProcessName))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Immediatly Return from Cache the Process Getter Calls * Performance Improvement *
|
||||
if (bUseLookupCache && s_processGetterCache.ContainsKey(ProcessName))
|
||||
return s_processGetterCache[ProcessName].ToArray();
|
||||
|
||||
// If a lookup cache is used, we won't deal with the complexity of also dealing with VSHost,
|
||||
// so ignore this setting
|
||||
if (bIgnoreVSHost && bUseLookupCache)
|
||||
bIgnoreVSHost = true;
|
||||
|
||||
// Running Processes found
|
||||
List<Diag.Process> runningProcess = new List<Diag.Process>();
|
||||
|
||||
// Regular Process Lookup...
|
||||
Diag.Process[] processes = Diag.Process.GetProcessesByName(ProcessName);
|
||||
if (processes != null && processes.Length > 0)
|
||||
{
|
||||
foreach (Diag.Process p in processes)
|
||||
runningProcess.Add(p);
|
||||
}
|
||||
|
||||
// Visual Studio could be running this...
|
||||
if (!bIgnoreVSHost)
|
||||
{
|
||||
processes = Diag.Process.GetProcessesByName(ProcessName + ".vshost");
|
||||
if (processes != null && processes.Length > 0)
|
||||
{
|
||||
foreach (Diag.Process p in processes)
|
||||
runningProcess.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Immediatly Cache the Process Getter Calls
|
||||
if (bUseLookupCache && !s_processGetterCache.ContainsKey(ProcessName))
|
||||
{
|
||||
s_processGetterCache[ProcessName] = new List<Diag.Process>();
|
||||
s_processGetterCache[ProcessName].AddRange(runningProcess);
|
||||
}
|
||||
|
||||
// Return the found Processes
|
||||
return runningProcess.ToArray();
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
}
|
||||
return new Diag.Process[0]{}; // return empty array
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Process Exe FileName N CommandLine Getters
|
||||
|
||||
/// <summary>
|
||||
/// Uses WMI to retrieve Process's FileNameNPath and the Command-Line Parameters for the specified Process
|
||||
/// </summary>
|
||||
/// <param name="ProcessId">a valid Pid to retrieve Command-line and Process FileName for</param>
|
||||
/// <param name="ProcessFileNameNPath">passing out full process exe file name and path for pid, if found</param>
|
||||
/// <param name="CommandLineParams">passing out CommandLine params for the Pid, if found</param>
|
||||
/// <returns>true, if the process was found and at least ProcessFileNameNPath was written out, false otherwise</returns>
|
||||
public static bool GetCommandLineArgumentsForProcessPID(int ProcessId, out string ProcessFileNameNPath, out string CommandLineParams)
|
||||
{
|
||||
ProcessFileNameNPath = String.Empty;
|
||||
CommandLineParams = String.Empty;
|
||||
try
|
||||
{
|
||||
// Use WMI to retrieve the info we need (.net does not provide any other way, it appears)
|
||||
string wmiQuery = string.Format("SELECT CommandLine from Win32_Process WHERE ProcessId = {0}", ProcessId);
|
||||
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmiQuery);
|
||||
ManagementObjectCollection retObjectCollection = searcher.Get();
|
||||
if ((retObjectCollection != null) && (retObjectCollection.Count > 0))
|
||||
{
|
||||
foreach (ManagementObject retObject in retObjectCollection) // This will always be only 1 * retObjectCollection doesn't implement []
|
||||
{
|
||||
if (retObject != null) // to be even more save...
|
||||
{
|
||||
string strLocal = String.Empty;
|
||||
if (retObject["CommandLine"] != null && !String.IsNullOrEmpty(retObject["CommandLine"].ToString()))
|
||||
strLocal = retObject["CommandLine"].ToString().Trim();
|
||||
|
||||
if (!String.IsNullOrEmpty(strLocal))
|
||||
{
|
||||
// This should work
|
||||
int firstQuotIndex = strLocal.IndexOf('\"');
|
||||
int SecondQuotIndex = (firstQuotIndex >= 0) ? strLocal.IndexOf('\"', firstQuotIndex + 1) : -1;
|
||||
|
||||
// Pass out * if we at least have a Process FileNameNPath *
|
||||
if (firstQuotIndex > -1 && SecondQuotIndex > -1)
|
||||
{
|
||||
ProcessFileNameNPath = Win32.Functions.GetLongFileNameNPathOrPath(strLocal.Substring(firstQuotIndex + 1, SecondQuotIndex - 1));
|
||||
CommandLineParams = (strLocal.Length > SecondQuotIndex + 2) ? strLocal.Substring(SecondQuotIndex + 2) : String.Empty;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Usefull for making sure that the exact Process Image (including Command-Line Prms) is currently in a running state.
|
||||
/// </summary>
|
||||
/// <param name="runningProcesses">Pass in a list of Process[] where to search for ProcessFileNameNPath and CommandLineParams</param>
|
||||
/// <param name="ProcessFileNameNPath">The exact Process FileName and Path (Image .exe) to find match for</param>
|
||||
/// <param name="CommandLineParams">The exact Command-Line Parameters to find match for</param>
|
||||
/// <param name="PID_Hint">a PID hint * to speed up look * caller can pass in a PID that 'most likely' is the PID we are looking for (Can be zero)</param>
|
||||
/// <param name="process">If we found the process match, we'll pass out the process to the caller (runningProcesses[]), null otherwise</param>
|
||||
/// <param name="indexFound">If we found the process match, we'll pass out the index to the caller (runningProcesses[]), -1 otherwise</param>
|
||||
/// <returns>True, if exact Match was found, False Otherwise</returns>
|
||||
public static bool FoundExactProcessExeNCommandLinePrmsInRunningProcesses(Diag.Process[] runningProcesses, string ProcessFileNameNPath, string CommandLineParams, int PID_Hint, out Diag.Process process, out int indexFound)
|
||||
{
|
||||
process = null;
|
||||
indexFound = -1;
|
||||
try
|
||||
{
|
||||
if (runningProcesses == null || runningProcesses.Length == 0)
|
||||
return false;
|
||||
|
||||
if (PID_Hint < 0)
|
||||
PID_Hint = 0;
|
||||
|
||||
bool bFoundProcessRunning = false;
|
||||
|
||||
// * For Performance Reasons * ProcessW.GetCommandLineArgumentsForProcessPID() takes a long time,
|
||||
// Use PID_Hint first, to check if that PID is it
|
||||
if (PID_Hint > 0)
|
||||
{
|
||||
for (int i = 0; i < runningProcesses.Length; ++i)
|
||||
{
|
||||
Diag.Process rProcess = runningProcesses[i];
|
||||
if (rProcess != null && (rProcess.Id == PID_Hint))
|
||||
{
|
||||
string ProcessFileNameNPath_Local;
|
||||
string CommandLineParams_Local;
|
||||
if (ProcessW.GetCommandLineArgumentsForProcessPID(rProcess.Id, out ProcessFileNameNPath_Local, out CommandLineParams_Local))
|
||||
{
|
||||
// See if we find a match
|
||||
if (ProcessFileExeNCommandLineParamsComparer_FoundMatch(ProcessFileNameNPath_Local, CommandLineParams_Local, ProcessFileNameNPath, CommandLineParams))
|
||||
{
|
||||
bFoundProcessRunning = true;
|
||||
process = rProcess;
|
||||
indexFound = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PID_Hint Worked, no need to continue...
|
||||
if (bFoundProcessRunning)
|
||||
return bFoundProcessRunning;
|
||||
|
||||
// Iterate all others
|
||||
for (int i = 0; i < runningProcesses.Length; ++i)
|
||||
{
|
||||
Diag.Process rProcess = runningProcesses[i];
|
||||
if (rProcess != null && (rProcess.Id != PID_Hint)) // Ignore PID_Hint * already been tried *
|
||||
{
|
||||
string ProcessFileNameNPath_Local;
|
||||
string CommandLineParams_Local;
|
||||
if (ProcessW.GetCommandLineArgumentsForProcessPID(rProcess.Id, out ProcessFileNameNPath_Local, out CommandLineParams_Local))
|
||||
{
|
||||
// See if we find a match
|
||||
if (ProcessFileExeNCommandLineParamsComparer_FoundMatch(ProcessFileNameNPath_Local, CommandLineParams_Local, ProcessFileNameNPath, CommandLineParams))
|
||||
{
|
||||
bFoundProcessRunning = true;
|
||||
process = rProcess;
|
||||
indexFound = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bFoundProcessRunning;
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the passed in ProcessExeFileNameNPath, CommandLinePrms match _Left and _Right
|
||||
/// </summary>
|
||||
/// <param name="ProcessFileNameNPath_Left">Process FileNameNPath to compare to Right</param>
|
||||
/// <param name="CommandLineParams_Left">CommandLine Parameters to compare to Right</param>
|
||||
/// <param name="ProcessFileNameNPath_Right">Process FileNameNPath to compare to Left</param>
|
||||
/// <param name="CommandLineParams_Right">CommandLine Parameters to compare to Left</param>
|
||||
/// <returns>true if _left and _right match, false otherwise</returns>
|
||||
public static bool ProcessFileExeNCommandLineParamsComparer_FoundMatch(string ProcessFileNameNPath_Left, string CommandLineParams_Left, string ProcessFileNameNPath_Right, string CommandLineParams_Right)
|
||||
{
|
||||
if ((String.Compare(ProcessFileNameNPath_Left.Trim(), ProcessFileNameNPath_Right.Trim(), true) == 0) &&
|
||||
(String.Compare(CommandLineParams_Left.Trim(), CommandLineParams_Right.Trim(), true) == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
212
Process/ServiceW.cs
Normal file
212
Process/ServiceW.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceProcess;
|
||||
using Yaulw.Win32;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Yaulw.Process
|
||||
{
|
||||
/// <remarks>
|
||||
/// Wrapper Class around System.ServiceProcess's ServiceControl Class,
|
||||
/// ~Little helper functions to make sure that we can safely interact with Services
|
||||
/// </remarks>
|
||||
public static class ServiceW
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks to see if the service exists on the local computer
|
||||
/// </summary>
|
||||
/// <param name="ServiceName">Name of Service to Check</param>
|
||||
/// <returns>true if it exists, false otherwise</returns>
|
||||
public static bool DoesServiceExist(string ServiceName)
|
||||
{
|
||||
try
|
||||
{
|
||||
ServiceController scm = new ServiceController(ServiceName);
|
||||
if (scm != null && !String.IsNullOrEmpty(scm.ServiceName))
|
||||
{
|
||||
scm.Dispose();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quick check to see if the service is running
|
||||
/// </summary>
|
||||
/// <param name="ServiceName">Name of Service to Check</param>
|
||||
/// <returns>true if the service is running, false otherwise, if it doesn't exist returns true</returns>
|
||||
public static bool IsServiceRunning(string ServiceName)
|
||||
{
|
||||
ServiceController scm = null;
|
||||
try
|
||||
{
|
||||
scm = new ServiceController(ServiceName);
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
|
||||
if (scm != null)
|
||||
{
|
||||
bool bIsRunning = (scm.Status == ServiceControllerStatus.Running);
|
||||
scm.Dispose();
|
||||
return bIsRunning;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this to Restart the Service
|
||||
/// </summary>
|
||||
/// <param name="ServiceName">Name of Service to Check</param>
|
||||
/// <param name="bKillServiceByForceIfNeedBe">Set to true to try to force a Service Close by killing the Process, if the service is hanging</param>
|
||||
/// <param name="WaitTimeoutInSeconds">Number of Seconds to wait for Service To Close/Start</param>
|
||||
/// <param name="nStartupDelayInSeconds">Number of Seconds to wait inbetween closing and starting</param>
|
||||
/// <returns>true if successful, false otherwise</returns>
|
||||
public static bool RestartService(string ServiceName, bool bKillServiceByForceIfNeedBe = true, int WaitTimeoutInSeconds = 240, int nStartupDelayInSeconds = 2)
|
||||
{
|
||||
// Stop the Service
|
||||
if (!StopService(ServiceName, bKillServiceByForceIfNeedBe, WaitTimeoutInSeconds))
|
||||
return false;
|
||||
|
||||
// Delay Starting the Services for 'n' seconds
|
||||
if (nStartupDelayInSeconds > 0)
|
||||
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(nStartupDelayInSeconds));
|
||||
|
||||
// Start the Service
|
||||
bool bIsStarted = StartService(ServiceName, WaitTimeoutInSeconds);
|
||||
return bIsStarted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this to start a service
|
||||
/// </summary>
|
||||
/// <param name="ServiceName">Name of Service to Check</param>
|
||||
/// <param name="WaitTimeoutInSeconds">Number of seconds to wait for Service to Start</param>
|
||||
/// <returns>true if successful, false otherwise</returns>
|
||||
public static bool StartService(string ServiceName, int WaitTimeoutInSeconds = 240)
|
||||
{
|
||||
ServiceController scm = null;
|
||||
try
|
||||
{
|
||||
scm = new ServiceController(ServiceName);
|
||||
|
||||
// Wait for 'Stopped' State
|
||||
if (scm.Status != ServiceControllerStatus.Running)
|
||||
{
|
||||
scm.Start();
|
||||
if (WaitTimeoutInSeconds > 0)
|
||||
scm.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(WaitTimeoutInSeconds));
|
||||
}
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
|
||||
if (scm != null)
|
||||
{
|
||||
bool bSuccess = (scm.Status == ServiceControllerStatus.Running);
|
||||
scm.Dispose();
|
||||
return bSuccess;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this to stop a service
|
||||
/// </summary>
|
||||
/// <param name="ServiceName">Name of Service to Check</param>
|
||||
/// <param name="bKillServiceByForceIfNeedBe">Set to true to try to force a Service Close by killing the Process, if the service is hanging</param>
|
||||
/// <param name="WaitTimeoutInSeconds">Number of seconds to wait for Service to Stop</param>
|
||||
/// <returns>true if successful, false otherwise</returns>
|
||||
public static bool StopService(string ServiceName, bool bKillServiceByForceIfNeedBe = true, int WaitTimeoutInSeconds = 240)
|
||||
{
|
||||
ServiceController scm = null;
|
||||
try
|
||||
{
|
||||
scm = new ServiceController(ServiceName);
|
||||
|
||||
// Wait for 'Stopped' State
|
||||
if (scm.Status != ServiceControllerStatus.Stopped)
|
||||
{
|
||||
scm.Stop();
|
||||
if (WaitTimeoutInSeconds > 0)
|
||||
scm.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(WaitTimeoutInSeconds));
|
||||
}
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
|
||||
try
|
||||
{
|
||||
if (scm != null)
|
||||
{
|
||||
bool bSuccess = (scm.Status == ServiceControllerStatus.Stopped);
|
||||
|
||||
// Always try Killing Service By Force, even if bSuccess is true,
|
||||
// just to try to guarantee that the service is dead for good
|
||||
if (bKillServiceByForceIfNeedBe)
|
||||
bSuccess = StopServiceByForce(scm) || bSuccess;
|
||||
|
||||
scm.Dispose();
|
||||
return bSuccess;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Brutal way to stop a service * Not Recommended *,
|
||||
/// according to article:
|
||||
/// </summary>
|
||||
/// <see cref="http://community.bartdesmet.net/blogs/bart/archive/2004/10/16/438.aspx"/>
|
||||
/// <see cref="http://stackoverflow.com/questions/884853/service-not-fully-stopped-after-servicecontroller-stop"/>
|
||||
/// <param name="scm">a Service Controller Object whose PID you would like to kill</param>
|
||||
/// <returns>true if successfull, false otherwise</returns>
|
||||
private static bool StopServiceByForce(ServiceController scm)
|
||||
{
|
||||
Structures.SERVICE_STATUS_PROCESS ssp = new Structures.SERVICE_STATUS_PROCESS();
|
||||
int ignored;
|
||||
|
||||
try
|
||||
{
|
||||
// Obtain information about the service, and specifically its hosting process,
|
||||
// from the Service Control Manager.
|
||||
if (!Advapi32.QueryServiceStatusEx(scm.ServiceHandle.DangerousGetHandle(), Definitions.SC_STATUS_PROCESS_INFO, ref ssp, Marshal.SizeOf(ssp), out ignored))
|
||||
{
|
||||
//throw new Exception("Couldn't obtain service process information.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// A few quick sanity checks that what the caller wants is *possible*.
|
||||
if (ssp.dwServiceType != Definitions.SERVICE_WIN32_OWN_PROCESS)
|
||||
{
|
||||
//throw new Exception("Can't wait for the service's hosting process to exit because there may be multiple services in the process (dwServiceType is not SERVICE_WIN32_OWN_PROCESS");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((ssp.dwServiceFlags & Definitions.SERVICE_RUNS_IN_SYSTEM_PROCESS) != 0)
|
||||
{
|
||||
//throw new Exception("Can't wait for the service's hosting process to exit because the hosting process is a critical system process that will not exit (SERVICE_RUNS_IN_SYSTEM_PROCESS flag set)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ssp.dwProcessId == 0)
|
||||
{
|
||||
//throw new Exception("Can't wait for the service's hosting process to exit because the process ID is not known.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try closing the Process Manually
|
||||
bool bCloseSuccess = PStarter.KillProcess((uint)ssp.dwProcessId, false, 1, false, 2);
|
||||
return bCloseSuccess;
|
||||
}
|
||||
catch (Exception) { /* ignore */ }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user