192

When I get a reference to a System.Diagnostics.Process, how can I know if a process is currently running?

one noa
  • 345
  • 1
  • 3
  • 10
reshefm
  • 6,017
  • 8
  • 36
  • 40

13 Answers13

305

This is a way to do it with the name:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
  MessageBox.Show("nothing");
else
  MessageBox.Show("run");

You can loop all process to get the ID for later manipulation:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
Patrick Desjardins
  • 136,852
  • 88
  • 292
  • 341
  • This is exactly what i was looking for. Even though this is a very old post, would you explain to me how this is valid C#. I am not doubting it, I see it works, but I have never seen if else without { }. – MatthewD Nov 18 '15 at 19:06
  • 8
    @MatthewD: C# `if/else` statements that are only one line in length don't need to have curly braces to indicate the block statement. This also goes for `foreach` and `for` statements. It boils down to coding style. – Hallmanac Nov 24 '15 at 01:36
  • 1
    I did some research on this too, found that info, but I didn't see the `for` info. Years of c# .net dev and I have never seen this style. Like they say, "you learn something new every day". Thank you for the post and the reply.. – MatthewD Nov 25 '15 at 03:06
  • 3
    @MatthewD yeah, this goes for most languages actually (like Java). It's generally good practice to avoid one-liners like these and always put curly braces, since there's always a chance you might have to add more statements there in the future, in which case the braces will already be there when you need them. But for things like this, if you are 100% sure you only need one statement, it's okay to do and syntactically valid. – David Mordigal Jul 03 '16 at 01:38
  • 2
    If you can't find the process, try removing the extension. (Ex: .exe) – DxTx Dec 30 '18 at 07:23
  • the first line of the code tells me : The name process does not exist in the current context – FroggyIsDank5 Mar 09 '20 at 11:45
  • @FroggyIsDank5 I know this is an old comment, but did you add the reference to `System.Diagnostics` at the top of your code? If you did, and it still doesn't work, you can try this: https://stackoverflow.com/a/28247780/6133426 – FiddlingAway Sep 22 '22 at 19:30
  • The variable name pName is a bad choice. A better name would be foundProcesses. The sample also would be better when the use of the process id was shown in the first bit of code. This way it would be clear how to find a process by name and get the Id of this process. – Jacob de Boer Jan 18 '23 at 09:17
36

This is the simplest way I found after using reflector. I created an extension method for that:

public static class ProcessExtensions
{
    public static bool IsRunning(this Process process)
    {
        if (process == null) 
            throw new ArgumentNullException("process");

        try
        {
            Process.GetProcessById(process.Id);
        }
        catch (ArgumentException)
        {
            return false;
        }
        return true;
    }
}

The Process.GetProcessById(processId) method calls the ProcessManager.IsProcessRunning(processId) method and throws ArgumentException in case the process does not exist. For some reason the ProcessManager class is internal...

reshefm
  • 6,017
  • 8
  • 36
  • 40
  • This was a really good answer; however, you shouldn't have through the argument null exception (Because a null reference exception would have been thrown anyway and you didn't do anything with the exception. Also, you will get an InvalidOperationException if you did not invoke the Start() method or you invoked the close() method. I posted another Answer to account for these two situations. – Aelphaeis Jan 31 '14 at 14:52
  • What if another process took the id of the original process that no longer running? Is it possible? – gil123 Jan 29 '21 at 19:44
19

Synchronous solution :

void DisplayProcessStatus(Process process)
{
    process.Refresh();  // Important


    if(process.HasExited)
    {
        Console.WriteLine("Exited.");
    }
    else
    {
        Console.WriteLine("Running.");
    } 
}

Asynchronous solution:

void RegisterProcessExit(Process process)
{
    // NOTE there will be a race condition with the caller here
    //   how to fix it is left as an exercise
    process.Exited += process_Exited;
}

static void process_Exited(object sender, EventArgs e)
{
   Console.WriteLine("Process has exited.");
}
Coincoin
  • 27,880
  • 7
  • 55
  • 76
  • 7
    For the first option: how can I know whether the process was started in the first place? – reshefm Nov 06 '08 at 11:39
  • Be aware it's possible `HasExited` throws an exception if something goes wrong (eg: exit code cannot be retrieved). – tigrou Jun 13 '23 at 14:05
12

reshefm had a pretty nice answer; however, it does not account for a situation in which the process was never started to begin with.

Here is a a modified version of what he posted.

public static bool IsRunning(this Process process)
{
    try
    {
        Process.GetProcessById(process.Id).Dispose();
    }
    catch (Exception e) when (e is ArgumentException or InvalidOperationException)
    {
        return false;
    }
    return true;
}

I removed his ArgumentNullException because its actually suppose to be a null reference exception and it gets thrown by the system anyway and I also accounted for the situation in which the process was never started to begin with or the close() method was used to close the process.

Scover
  • 93
  • 9
Aelphaeis
  • 2,593
  • 3
  • 24
  • 42
  • Personally, I would much rather see an ArgumentNullException when reviewing a logged exception than a NullReferenceException, since ArgumentNullException is much more explicit about what went wrong. – Sean Apr 27 '16 at 18:40
  • 1
    @Sean I would normally agree with you but this is an extension method. I think it is more appropriate to throw a null pointer exception given the syntax, it just feels more consistent with calling methods of null objects. – Aelphaeis Apr 28 '16 at 15:30
  • This will trigger FirstHandledException event handler every time. Way to spam your logs there buddy. – Latency Apr 13 '19 at 21:12
12

This should be a one-liner:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
guneysus
  • 6,203
  • 2
  • 45
  • 47
3

It depends on how reliable you want this function to be. If you want to know if the particular process instance you have is still running and available with 100% accuracy then you are out of luck. The reason being that from the managed process object there are only 2 ways to identify the process.

The first is the Process Id. Unfortunately, process ids are not unique and can be recycled. Searching the process list for a matching Id will only tell you that there is a process with the same id running, but it's not necessarily your process.

The second item is the Process Handle. It has the same problem though as the Id and it's more awkward to work with.

If you're looking for medium level reliability then checking the current process list for a process of the same ID is sufficient.

Jan
  • 108
  • 1
  • 7
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1
string process = "notepad";
if (Process.GetProcessesByName(process).Length > 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

also you can use a timer for checking the process every time

Rich
  • 12,068
  • 9
  • 62
  • 94
berkay
  • 27
  • 1
1

Process.GetProcesses() is the way to go. But you may need to use one or more different criteria to find your process, depending on how it is running (i.e. as a service or a normal app, whether or not it has a titlebar).

Pure.Krome
  • 84,693
  • 113
  • 396
  • 647
Jeff Kotula
  • 2,114
  • 12
  • 16
  • 1
    If you put this method in a loop, it costs a lot of CPU cycles. I recommend to use GetProcessByName() or GetProcessByID(). – Hao Nguyen Jul 08 '16 at 16:55
1

There are many problems associated with this, as other have seemed to partially address:

  • Any instance members are not guaranteed to be thread safe. Meaning there are race conditions that may occur with the lifetime of the snapshot while trying to evaluate the properties of the object.
  • The process handle will throw Win32Exception for ACCESS DENIED where permissions for evaluating this and other such properties aren't allowed.
  • For ISN'T RUNNING status, an ArgumentException will also be raised when trying to evaluate some of its properties.

Whether the properties others have mentioned are internal or not, you can still obtain information from them via reflection if permission allows.

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

You could pinvoke Win32 code for Snapshot or you can use WMI which is slower.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Another option would be to OpenProcess / CloseProcess, but you will still run into the same issues with exceptions being thrown same as before.

For WMI - OnNewEvent.Properties["?"]:

  • "ParentProcessID"
  • "ProcessID"
  • "ProcessName"
  • "SECURITY_DESCRIPTOR"
  • "SessionID"
  • "Sid"
  • "TIME_CREATED"
Latency
  • 426
  • 3
  • 12
0

I tried Coincoin's solution :
Before processing some file, I copy it as a temporary file and open it.
When I'm done, I close the application if it is still open and delete the temporary file :
I just use a Process variable and check it afterwards :

private Process openApplication;  
private void btnOpenFile_Click(object sender, EventArgs e) {  
    ...
    // copy current file to fileCache  
    ...  
    // open fileCache with proper application
    openApplication = System.Diagnostics.Process.Start( fileCache );  
}

Later I close the application :

 ...   
openApplication.Refresh(); 

// close application if it is still open       
if ( !openApplication.HasExited() ) {
    openApplication.Kill();  
}

// delete temporary file  
System.IO.File.Delete( fileCache );

It works ( so far )

Jack Griffin
  • 1,228
  • 10
  • 17
  • 3
    At `openApplication.HasExited()`, HasExited is not a function. The correct way would be `openApplication.HasExited`. – caiosm1005 Dec 30 '13 at 04:24
0

Maybe (probably) I am reading the question wrongly, but are you looking for the HasExited property that will tell you that the process represented by your Process object has exited (either normally or not).

If the process you have a reference to has a UI you can use the Responding property to determine if the UI is currently responding to user input or not.

You can also set EnableRaisingEvents and handle the Exited event (which is sent asychronously) or call WaitForExit() if you want to block.

0

Despite of supported API from .Net frameworks regarding checking existing process by process ID, those functions are very slow. It costs a huge amount of CPU cycles to run Process.GetProcesses() or Process.GetProcessById/Name().

A much quicker method to check a running process by ID is to use native API OpenProcess(). If return handle is 0, the process doesn't exist. If handle is different than 0, the process is running. There's no guarantee this method would work 100% at all time due to permission.

Hao Nguyen
  • 528
  • 4
  • 10
  • How slow would it be, if GetProcessById is called everytime a new window is opened? – demberto Jul 03 '22 at 15:34
  • It may help to provide an order of magnitude for the claim that GetProcessByName, etc. are slow. In BenchmarkDotNet, GetProcessByName took 5 ms on my machine (.NET 7). – Andrew D. Bond May 08 '23 at 09:20
0

You can instantiate a Process instance once for the process you want and keep on tracking the process using that .NET Process object (it will keep on tracking till you call Close on that .NET object explicitly, even if the process it was tracking has died [this is to be able to give you time of process close, aka ExitTime etc.])

Quoting http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx:

When an associated process exits (that is, when it is shut down by the operation system through a normal or abnormal termination), the system stores administrative information about the process and returns to the component that had called WaitForExit. The Process component can then access the information, which includes the ExitTime, by using the Handle to the exited process.

Because the associated process has exited, the Handle property of the component no longer points to an existing process resource. Instead, the handle can be used only to access the operating system’s information about the process resource. The system is aware of handles to exited processes that have not been released by Process components, so it keeps the ExitTime and Handle information in memory until the Process component specifically frees the resources. For this reason, any time you call Start for a Process instance, call Close when the associated process has terminated and you no longer need any administrative information about it. Close frees the memory allocated to the exited process.

George Birbilis
  • 2,782
  • 2
  • 33
  • 35