61

I am starting Internet Explorer programmatically with code that looks like this:

ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);

This generates 2 processes visible in the Windows Task Manager. Then, I attempt to kill the process with:

ieProcess.Kill();

This results in one of the processes in Task Manager being shut down, and the other remains. I tried checking for any properties that would have children processes, but found none. How can I kill the other process also? More generally, how do you kill all the processes associated with a process that you start with Process.Start?

Cœur
  • 37,241
  • 25
  • 195
  • 267
robr
  • 919
  • 1
  • 7
  • 16

11 Answers11

88

This worked very nicely for me:

/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
private static void KillProcessAndChildren(int pid)
{
    // Cannot close 'system idle process'.
    if (pid == 0)
    {
        return;
    }
    ManagementObjectSearcher searcher = new ManagementObjectSearcher
            ("Select * From Win32_Process Where ParentProcessID=" + pid);
    ManagementObjectCollection moc = searcher.Get();
    foreach (ManagementObject mo in moc)
    {
        KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
    }
    try
    {
        Process proc = Process.GetProcessById(pid);
        proc.Kill();
    }
    catch (ArgumentException)
    {
        // Process already exited.
    }
}

Update 2016-04-26

Tested on Visual Studio 2015 Update 2 on Win7 x64. Still works as well now as it did 3 years ago.

Update 2017-11-14

Added check for system idle process if (pid == 0)

Update 2018-03-02

Need to add a reference to the System.Management namespace, see comment from @MinimalTech below. If you have ReSharper installed, it will offer to do this for you automatically.

Update 2018-10-10

The most common use case for this is killing any child processes that our own C# process has started.

In this case, a better solution is to use Win32 calls within C# to make any spawned process a child process. This means that when the parent process exits, any child processes are automatically closed by Windows, which eliminates the need for the code above. Please let me know if you want me to post the code.

Contango
  • 76,540
  • 58
  • 260
  • 305
  • What about grandchildren? Methinks this should be a recursive method. – kerem Jul 17 '13 at 14:31
  • 10
    @kerem erm I think it is – Dave Lawrence Feb 21 '14 at 11:01
  • What if `E_ACCESSDENIED` while listing processes? – Mygod Jan 17 '17 at 16:21
  • 5
    You are great!! Working like a charm with .NET 4.0 and VS2010. Just to note for someone (like me) that didn't know, you have to use System.Management namespace. But to be able to use it, you must go to your project name -> rightclick to it -> add reference -> .NET -> and select System.Management assembly as @Femaref note it here: https://stackoverflow.com/questions/3692384/missing-directive-or-assembly-reference-using-wmi-managementobjectsearcher – MinimalTech Mar 01 '18 at 21:56
  • Warning, if you call this method regulary, it will lead to the wmiprvsv.exe consuming 40-100% of the CPU. – Daniel Vygolov Jul 21 '18 at 12:54
  • @Daniel Vygolov Good to know. Its probably the select statement that is doing it. Not sure why one would call this regularly, the only use cases I can think of are clean-up type operations. Wondering why one would need to call this regularly? – Contango Jul 21 '18 at 21:01
  • @DanielVygolov Is there a better solution if I need to call this regularly? – KaiserKatze Oct 15 '18 at 11:41
  • @KaiserKatze See my update above, is this applicable? – Contango Oct 16 '18 at 12:19
  • Shouldn't it be ```InvalidOperationException``` instead of ```ArgumentException```? – rsmith54 Apr 29 '20 at 21:25
  • Perhaps - it depends on what exceptions can possibly by thrown, and if they should be ignored or not. If you are observing an InvalidOperationException, then it might make sense to add an extra handler. The exception might vary by the .NET framework installed, and might change with .NET Core. Both of these exceptions inherit from `SystemException`, so adding a handler for that might do the job as well. – Contango Apr 30 '20 at 12:12
  • 2
    Note that Windows reuses Process Ids. If a process spawns child processes and quits leaving its children running, and then your process reuses the original process's id, then it will appear to have additional children. The above method will then attempt to kill these also (it may or may not have permission). One solution is to add a check of the time a process started and confirm it was after the root process in the tree to be killed. – EddPorter Aug 27 '20 at 08:04
34

If anyone needs a dotnet core solution,

Dotnet core 3.0

process.Kill(true);

See official documentation

Dotnet core 2.0

For .Net 2.0 dotnet cli came up with an implementation based on taskill as mentioned above and recursive pgrep/kill for unix based systems. Full implementation can be found on github. Sadly, the class is internal so you'll have to copy it into your code base.

List Child processes (has to be done recursively):

$"pgrep -P {parentId}"

Kill on process:

$"kill -TERM {processId}"
Cyprien Autexier
  • 1,948
  • 16
  • 20
16

I'm not a fan of any of the solutions presented here.

Here's what I came up with:

private static void EndProcessTree(string imageName)
{
    Process.Start(new ProcessStartInfo
    {
        FileName = "taskkill",
        Arguments = $"/im {imageName} /f /t",
        CreateNoWindow = true,
        UseShellExecute = false
    }).WaitForExit();
}

How to use:

EndProcessTree("chrome.exe");
Owen
  • 321
  • 2
  • 12
  • 4
    From experience working on a compiling automation program, this will be very dangerous in a production environment where multiple processes are run in parallel. Simple example: Try to kill explorer.exe, or cmd.exe. A good portion of the user environment will evaporate. – Xenhat Aug 22 '19 at 23:00
  • This didn't work at all. Process.GetProcessByName() returned the information was there, but calling this didn't fail, just didn't do anything. – Chizl Mar 09 '20 at 11:40
  • Your code was copied and pasted. Passes chrome.exe like you did. Don't think taskkill is a standard windows utility and didn't fire on my windows 10 machine. – Chizl Mar 14 '20 at 13:42
10

You should call Process.CloseMainWindow() which will send a message to the main window of the process. Think of it as having the user click the "X" close button or File | Exit menu item.

It is safer to send a message to Internet Explorer to close itself down, than go and kill all its processes. Those processes could be doing anything and you need to let IE do its thing and finish before just killing it in the middle of doing something that may be important for future runs. This goes true for any program you kill.

Pierre Arnaud
  • 10,212
  • 11
  • 77
  • 108
Kerry Kobashi
  • 109
  • 1
  • 2
9

If anyone is interested, I took one of the answers from the other page and modified it slightly. It is a self contained class now with static methods. It does not have proper error handling or logging. Modify to use for your own needs. Providing your root Process to KillProcessTree will do it.

class ProcessUtilities
{
    public static void KillProcessTree(Process root)
    {
        if (root != null)
        {
            var list = new List<Process>();
            GetProcessAndChildren(Process.GetProcesses(), root, list, 1);

            foreach (Process p in list)
            {
                try
                {
                    p.Kill();
                }
                catch (Exception ex)
                {
                    //Log error?
                }
            }
        }
    }

    private static int GetParentProcessId(Process p)
    {
        int parentId = 0;
        try
        {
            ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
            mo.Get();
            parentId = Convert.ToInt32(mo["ParentProcessId"]);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            parentId = 0;
        }
        return parentId;
    }

    private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
    {
        foreach (Process p in plist)
        {
            if (GetParentProcessId(p) == parent.Id)
            {
                GetProcessAndChildren(plist, p, output, indent + 1);
            }
        }
        output.Add(parent);
    }
}
robr
  • 919
  • 1
  • 7
  • 16
7

Another solution is to use the taskill command. I use the next code in my applications:

public static void Kill()
{
    try
    {
            ProcessStartInfo processStartInfo = new ProcessStartInfo("taskkill", "/F /T /IM your_parent_process_to_kill.exe")
            {
                WindowStyle = ProcessWindowStyle.Hidden,
                CreateNoWindow = true,
                UseShellExecute = false,
                WorkingDirectory = System.AppDomain.CurrentDomain.BaseDirectory,
                RedirectStandardOutput = true,
                RedirectStandardError = true
            };
            Process.Start(processStartInfo);
    }
    catch { }
}
Juan Carlos Velez
  • 2,840
  • 2
  • 34
  • 48
4

Are you using IE8 or IE9? That would absolutely start more than one process due to its new multi-process architecture. Anyway, have a look at this other answer for getting a process tree and killing it.

Community
  • 1
  • 1
  • Yes, this answers both why 2 processes start, and how to kill the process tree. Somehow I couldn't find this earlier, thanks. – robr May 05 '11 at 17:31
  • Although, I have to admit, I was expecting it to be a lot simpler. Barf. – robr May 05 '11 at 17:33
  • @robr: If the code works, it should be a simple copy and paste away from success. –  May 05 '11 at 17:34
3

Another approach that can be very useful is using the Windows API for Job Objects. A process can be assigned to a job object. The child processes of such a process are automatically assigned to the same job object.

All processes assigned to a job object can be killed at once e.g. with TerminateJobObject which:

Terminates all processes currently associated with the job.

The C# example in this answer (based on this answer) uses the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag instead, which:

Causes all processes associated with the job to terminate when the last handle to the job is closed.

Community
  • 1
  • 1
Peter
  • 3,322
  • 3
  • 27
  • 41
3

With .NET Core 3.0 there is a method just for that, namely new overload of the already existing Process.Kill() method. IOW, doing process.Kill(true) on the variable process of type Process kills the process with all its descendants. This is cross-platform, naturally.

konrad.kruczynski
  • 46,413
  • 6
  • 36
  • 47
  • Has this been verified as working correctly on Linux? The documentation (https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.kill?view=netstandard-2.1) refers to many Windows specifics. – 0b101010 Jan 22 '20 at 12:19
  • Further to previous comment, I found this (https://developers.redhat.com/blog/2019/10/29/the-net-process-class-on-linux/). Looks like things are badly crippled for Linux... – 0b101010 Jan 22 '20 at 12:21
  • @0b101010 Which part exactly tells that killing process tree is badly crippled for Linux? – konrad.kruczynski Jan 22 '20 at 20:53
  • Here is the commit that adds this feature, showing its cross-platform availability: https://github.com/dotnet/runtime/commit/7bc0c52080b42f1196ee38f7e7501270fefb6dea (Search for KillTree). – konrad.kruczynski Jan 22 '20 at 21:01
  • I was referring to the full functionality of the `Process` class as documented in that RedHat blog post. – 0b101010 Jan 23 '20 at 10:10
  • @0b101010 There are some caveats in the `Process` class in general, but the tree killing feature works well on Linux (as well as on other OSes). – konrad.kruczynski Jan 24 '20 at 11:08
1

As per documentation

The Kill method executes asynchronously. After calling the Kill method, call the WaitForExit method to wait for the process to exit, or check the HasExited property to determine if the process has exited.

ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
ieProcess.Kill();
ieProcess.WaitForExit();
Sameh
  • 1,318
  • 11
  • 11
  • Does this actually address the multiple threads problem though? It has been 9 years since I last dealt with this, so I may be forgetting, but not sure this would fix? – robr Aug 12 '20 at 13:44
  • This addresses that even after you kill a process by calling Kill method , your routine may still pick it up if it calls GetProcessById because it didn't wait until the process exits – Sameh Aug 12 '20 at 17:23
0

How to properly close Internet Explorer when launched from PowerShell?

Several of those commented in the above thread that this is caused by a bug in Win7 (as it does not seem to occur for users that are using other versions of windows). Many pages on the internet, including microsoft's page claim user error, and tell you to simply use the available quit method on the IE object which is SUPPOSED to close all child processes as well (and reportedly does in Win8/XP etc)

I must admit, for my part, it WAS user error. I am in win7 and the reason the quit method was not working for me was because of an error in coding. Namely I was creating the IE object at declaration, and then creating another (attached to the same object) later on in the code... I had almost finished hacking the parent-child killing routine to work for me when I realized the issue.

Because of how IE functions, the processID you spawned as the parent could be attached to other windows/subprocesses that you did NOT create. Use quit, and keep in mind that depending on user settings (like empty cache on exit) it could take a few minutes for the processes to finish their tasks and close.

Community
  • 1
  • 1