310 lines
16 KiB
C#
310 lines
16 KiB
C#
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
|
|
}
|
|
}
|