web-dev-qa-db-ja.com

C#でプログラムでプロセスツリーを強制終了する

次のようなコードでプログラム的にInternet Explorerを起動しています。

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

これにより、Windowsタスクマネージャーに表示される2つのプロセスが生成されます。次に、プロセスを強制終了します:

ieProcess.Kill();

これにより、タスクマネージャーのプロセスの1つがシャットダウンされ、残りのプロセスが残ります。子プロセスを持つプロパティをチェックしようとしましたが、何も見つかりませんでした。他のプロセスも強制終了できますか?より一般的には、Process.Startで開始したプロセスに関連付けられているすべてのプロセスをどのように強制終了しますか?

38
robr

これは私にとって非常にうまくいきました:

_/// <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.
    }
}
_

更新2016-04-26

_Visual Studio 2015 Update 2_で_Win7 x64_でテスト済み。 3年前と同じように機能します。

更新2017-11-14

システムアイドルプロセスif (pid == 0)のチェックを追加

更新2018-03-02

_System.Management_名前空間への参照を追加する必要があります。以下の@MinimalTechからのコメントを参照してください。 ReSharperがインストールされている場合は、自動的にこれを行うように提案されます。

2018-10-10の更新

これの最も一般的な使用例は、独自のC#プロセスが開始したすべての子プロセスを強制終了することです。

この場合、C#内でWin32呼び出しを使用して、生成されたプロセスを子プロセスにすることをお勧めします。つまり、親プロセスが終了すると、すべての子プロセスがWindowsによって自動的に閉じられるため、上記のコードは不要になります。コードを投稿してほしい場合はお知らせください。

60
Contango

私はここで紹介したソリューションのどれも好きではありません。

ここに私が思いついたものがあります:

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

使用方法:

EndProcessTree("chrome.exe");
11
Owen

誰かがドットネットコアソリューションを必要とする場合、dotnet cliは、上記のtaskillと再帰的pgrep/killUNIXベースのシステムの場合。 完全な実装はgithubにあります 。悲しいことに、クラスは内部にあるため、コードベースにコピーする必要があります。

子プロセスをリストします(再帰的に実行する必要があります):

$"pgrep -P {parentId}"

プロセスで強制終了:

$"kill -TERM {processId}"
11

プロセスのメインウィンドウにメッセージを送信するProcess.CloseMainWindow()を呼び出す必要があります。ユーザーが「X」閉じるボタンをクリックするか、またはFile | 終了メニュー項目。

すべてのプロセスを終了するよりも、Internet Explorerにメッセージを送信して自身を閉じる方が安全です。これらのプロセスは何でもできるので、IEをさせて、将来の実行に重要かもしれない何かをする途中でそれを殺す前に終了させる必要があります。これはどのプログラムにも当てはまります。あなたは殺します。

10
Kerry Kobashi

誰かが興味があるなら、私は他のページから答えの1つを取り、それをわずかに修正しました。これは、静的メソッドを備えた自己完結型のクラスです。 notは、適切なエラー処理またはロギングを行います。独自のニーズに合わせて変更してください。ルートプロセスをKillProcessTreeに提供することで実行できます。

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);
    }
}
7
robr

別の解決策は、taskillコマンドを使用することです。アプリケーションで次のコードを使用します。

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 { }
}
6

IE8またはIE9を使用していますか?新しいマルチプロセスアーキテクチャにより、複数のプロセスが完全に開始されます。とにかく、プロセスツリーを取得して強制終了するための この他の回答 をご覧ください。

4

非常に便利な別のアプローチは、 ジョブオブジェクトのWindows API を使用することです。プロセスをジョブオブジェクトに割り当てることができます。このようなプロセスの子プロセスは、同じジョブオブジェクトに自動的に割り当てられます。

ジョブオブジェクトに割り当てられたすべてのプロセスは、一度に強制終了できます。 TerminateJobObject which:

現在ジョブに関連付けられているすべてのプロセスを終了します。

この回答のC#の例この回答に基づいて )は、代わりに JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE フラグを使用します。

ジョブの最後のハンドルが閉じられると、ジョブに関連付けられているすべてのプロセスが終了します。

2
Peter

PowerShellから起動したときにInternet Explorerを適切に閉じる方法

これらのいくつかは、Win7のバグが原因であると上記のスレッドでコメントしています(他のバージョンのWindowsを使用しているユーザーには発生しないようです)。 Microsoftのページを含むインターネット上の多くのページは、ユーザーエラーを主張し、IE Win8/XPなどで)

私は、それがユーザーエラーであったことを認めなければなりません。私はwin7を使用していますが、quitメソッドが機能しなかったのは、コーディングのエラーが原因でした。つまり、宣言時にIEオブジェクトを作成し、その後コード内で別の(同じオブジェクトにアタッチされた)オブジェクトを作成していました...問題に気付いたときに私のために働いてください。

IEが機能するため、親として生成したprocessIDは、作成しなかった他のウィンドウ/サブプロセスにアタッチできます。quitを使用し、ユーザー設定によっては終了時にキャッシュを空にする)プロセスがタスクを完了して閉じるまでに数分かかる場合があります。

0
Jack Hadley