Reputation: 8350
I am using the below code to look up for any new process started. This function is running in the thread.
I need to log in the process name started. For which I use two arraylist. On one arraylist i store all the process names before it starts the thread and the other arraylist, I fill the current process inside the thread and compare two arraylist to find the new process.
The problem now is, since the string to write to the log file is in for each loop, I see repeated process names in the log file. I want it to be logged only once. How can I solve this?
class ProcessMonitor
{
public static ArrayList ExistingProcess = new ArrayList();
public static void Monitor()
{
existingProcesses = GetExistingProcess();
while (true)
{
ArrayList currentProcesses = new ArrayList();
currentProcesses = GetCurrentProcess();
ArrayList NewApps = new ArrayList(GetCurrentProcess());
foreach (var p in ExistingProcess)
{
NewApps.Remove(p);
}
string str = "";
foreach (string NewApp in NewApps)
{
str += "Launched ProcessName/ID : " + NewApp + "/" + System.Diagnostics.Process.GetProcessesByName(NewApp)[0].Id.ToString() + Environment.NewLine;
}
if(str!="")
{
Log.Info(str);
}
}
}
public static ArrayList GetExistingProcess()
{
Process[] processlist = Process.GetProcesses();
foreach (Process Proc in processlist)
{
ExistingProcess.Add(Proc.ProcessName);
}
return ExistingProcess;
}
public static ArrayList GetCurrentProcess()
{
ArrayList CurrentProcesses = new ArrayList();
Process[] processlist = Process.GetProcesses();
foreach (Process Proc in processlist)
{
CurrentProcesses.Add(Proc.ProcessName);
}
return CurrentProcesses;
}
}
Upvotes: 3
Views: 2753
Reputation: 941257
Iterating processes is very expensive on Windows. There's a better way to do it with WMI, Win32_ProcessStartTrace class. It also automatically solves your problem since it will only tell you about new processes getting started. And doesn't need a thread.
You'll find the code you need in this answer.
Upvotes: 4
Reputation: 32950
I'm not exactly sure what you are doing here, but the first two lines and the last line from the excerpt below basically do the same thing, only the last line is more costly (since your creating a second array list from the one returned by GetCurrentProcess
:
ArrayList currentProcesses = new ArrayList();
currentProcesses = GetCurrentProcess();
ArrayList NewApps = new ArrayList(GetCurrentProcess());
Second, you never seem to use the currentProcess
variable as far as I can tell...so its 100% waste. Third, why is it a problem if there are duplicates of process names? The same process can be started more than once, more than one instance of a process may be running concurrently, a process may run, be stopped, then be run again, etc. It is not necessarily "incorrect" for a process name to be listed twice.
(UPDATE: One reason why you may be getting "duplicates" in your log is that you get existingProcesses
only once. Every time through the loop (which, btw, will happen at maximum speed continuously), you will be getting the list of processes again, and comparing them with the original existingProcesses
, so the same processes listed in the previous loop...if they are still running, will be listed again. I've updated my code example to demonstrate how to solve this problem.)
You seem to have some fundamental code errors, and possibly flaws in your expectations. I would revisit your code in general, eliminate useless code (like the first two lines above), and generally streamline your code. (Hint: ArrayList
is a REALLY bad choice...I would use IEnumerable<T>
, which does not require ANY conversion or population from a raw Array). If I were to duplicate the code above with more efficient code:
public static void Monitor()
{
var existingProcesses = Process.GetProcesses();
bool doProcessing = true;
while (doProcessing)
{
var currentProcesses = Process.GetProcesses();
var newProcesses = currentProcesses.Except(existingProcesses);
int capacity = newProcesses.Count() * 60;
var builder = new StringBuilder(capacity);
foreach (var newProcess in newProcesses)
{
builder.Append("Launched ProcessName/ID : ");
builder.Append(newProcess.ProcessName);
builder.Append("/");
builder.Append(newProcess.Id);
builder.AppendLine();
}
string newProcessLogEntry = builder.ToString();
if(!String.IsNullOrEmpty(newProcessLogEntry))
{
Log.Info(newProcessLogEntry);
}
existingProcesses = currentProcesses; // Update existing processes, so you don't reprocess previously processed running apps and get "duplicate log entries"
if (requestToStopMonitoring) // do something to kill this loop gracefully at some point
{
doProcessing = false;
continue;
}
Thread.Sleep(5000); // Wait about 5 seconds before iterating again
}
}
Upvotes: 1