.Net Events for Process Executable Start

.NET Events for Process executable start

You could use the following:

    private ManagementEventWatcher WatchForProcessStart(string processName)
{
string queryString =
"SELECT TargetInstance" +
" FROM __InstanceCreationEvent " +
"WITHIN 10 " +
" WHERE TargetInstance ISA 'Win32_Process' " +
" AND TargetInstance.Name = '" + processName + "'";

// The dot in the scope means use the current machine
string scope = @"\\.\root\CIMV2";

// Create a watcher and listen for events
ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
watcher.EventArrived += ProcessStarted;
watcher.Start();
return watcher;
}

private ManagementEventWatcher WatchForProcessEnd(string processName)
{
string queryString =
"SELECT TargetInstance" +
" FROM __InstanceDeletionEvent " +
"WITHIN 10 " +
" WHERE TargetInstance ISA 'Win32_Process' " +
" AND TargetInstance.Name = '" + processName + "'";

// The dot in the scope means use the current machine
string scope = @"\\.\root\CIMV2";

// Create a watcher and listen for events
ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
watcher.EventArrived += ProcessEnded;
watcher.Start();
return watcher;
}

private void ProcessEnded(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject targetInstance = (ManagementBaseObject) e.NewEvent.Properties["TargetInstance"].Value;
string processName = targetInstance.Properties["Name"].Value.ToString();
Console.WriteLine(String.Format("{0} process ended", processName));
}

private void ProcessStarted(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject targetInstance = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value;
string processName = targetInstance.Properties["Name"].Value.ToString();
Console.WriteLine(String.Format("{0} process started", processName));
}

You would then call either WatchForProcessStart and/or WatchForProcessEnd passing in your process name (eg "notepad.exe").

The ManagementEventWatcher object is returned from the two Watch* methods as it implements IDisposable and so you should call Dispose on these objects when you have finished with them to prevent issues.

You could also change the polling value in the queries if you need the event to be raised more quickly after the process has started. To do this change the line "WITHIN 10" to be WITHIN something less than 10.

Is there a System event when processes are created?

WMI gives you a means to listen for process creation (and about a million other things). See my answer here.

 void WaitForProcess()
{
ManagementEventWatcher startWatch = new ManagementEventWatcher(
new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
startWatch.EventArrived
+= new EventArrivedEventHandler(startWatch_EventArrived);
startWatch.Start();
}

static void startWatch_EventArrived(object sender, EventArrivedEventArgs e)
{
Console.WriteLine("Process started: {0}"
, e.NewEvent.Properties["ProcessName"].Value);
if (this is the process I'm interested in)
{
startWatch.Stop();
}
}

What is the event which raise when a processes comes up

There is no event raised when a process starts. The best you can do is poll using EnumProcesses - here's a CodeProject article about doing so.

Raise event in C# when another process exits

If you are using C# 4.0 you can do something like:

 Task.Factory.StartNew(() => 
{
var process = Process.Start("process.exe");
process.WaitForExit();
}).ContinueWith(

//THE CODE THAT WILL RUN AFTER PROCESS EXITED.

);

EDIT

If you are not creator of a process, you can use Process.GetProcessesByName function to retrive the process from already available ones.

var process = Process.GetProcessesByName("process.exe");

In this way you can avoid blocking your main thread, and run the code you need at the moment external process exited. Meanwhile, continue do something more important.

.NET Process.Start() close event from child process

If that is possible to edit p1 process to wait the completion of p2 - that will be the simplest solution. In this case you can start p1 in 'no window' mode and wait its completion.

If that is not possible, then you can still find all processes started by p1 by using process parent id:

p1.WaitForExit();
var p1Id = p1.Id;
var subProcesses = Process.GetProcesses().Where(p => {
var indexedName = ProcessExtensions.FindIndexedProcessName(p.Id);
var parentIdCounter = new PerformanceCounter("Process", "Creating Process ID", indexedName);
var parentId = (int)parentIdCounter.NextValue();
return parentId == p1Id;
}).ToArray();
subProcesses.Select(_ => _.Id).ToList().ForEach(Console.WriteLine);

If you know UI application name and there could not be started more than 1 application for the user, then you can ignore parent id check and just find process by its name.

Is there a way to attach an event handler to the list of running processes in C#?

You can also use WMI Events to track this.

Here is an example:

static void Main(string[] args)
{
var query = new EventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance isa \"Win32_Process\"");

using (var eventWatcher = new ManagementEventWatcher(query))
{
eventWatcher.EventArrived += eventWatcher_EventArrived;
eventWatcher.Start();
Console.WriteLine("Started");
Console.ReadLine();
eventWatcher.EventArrived -= eventWatcher_EventArrived;
eventWatcher.Stop();
}
}

static void eventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
{
try
{
var instanceDescription = e.NewEvent.GetPropertyValue("TargetInstance") as ManagementBaseObject;
if(instanceDescription!=null)
{
var executablePath = instanceDescription.GetPropertyValue("ExecutablePath");
if(executablePath!=null)
{
Console.WriteLine("Application {0} started", executablePath.ToString());
}
}
}
catch (ManagementException) { }
}

There are a lot of process attributes that can be received. Like Priority, Description, Command Line arguments, etc. You can look in instanceDescription.Properties for details.

C# monitor external process state

Make a timer (with your preferred timer method) and poll every 'n' milliseconds (find what's best for you... I'd say for minimizing/restoring from a game, 500 milliseconds could be a good start, but experiment), then you can use something like:

 bool processRunning = false;

void timerTickMethod()
{
var procIsRunning = Process.GetProcessesByName("xyz.exe").Any();

if(procIsRunning && !processRunning)
ProcessIsStartedEvent(); // or directly minimize your app
else if(!procIsRuning && processRunning)
ProcessIsEndedEvent(); // or directly restore your app

processRunning = procIsRunning;
}

If you want to make sure it's your xyz.exe that is running, you can pass in the full path to GetProcessesByName (so that if there's other xyz.exe in your system, it won't confuse your app)

Update

I was writing from memory, so maybe GetProcessesByName only work for friendly names (with no exe, or path).

If that's the case (I haven't tried), and you need the full path you could do it like:

var procIsRunning = Process.GetProcesses().Any(x => x.MainModule.Filename == @"c:\your\full\path.exe");

How to detect when a running process starts another

If you are wanting to do this programmatically it is a tricky task but still doable, you would need to get every process that is running and find it's parent process ID. Then compare to the previous check if it is new.

If you simply want to find out about a specific program try this application by Microsoft:
Process Monitor



Related Topics



Leave a reply



Submit