2009-03-10 46 views
7

Về cơ bản quy trình con chạy vô thời hạn cho đến khi bị chết ở chế độ nền và tôi muốn xóa sạch chương trình khi chương trình của tôi chấm dứt vì bất kỳ lý do gì, tức là thông qua Taskmanager. Count()> 0) vòng lặp và thoát ra nếu quá trình cha mẹ không chạy, nhưng nó có vẻ khá giòn, và nếu tôi muốn nó hoạt động dưới trình gỡ lỗi trong Visual Studio tôi phải thêm "ParentProcess.vshost" hoặc một cái gì đó.Có cách nào để đảm bảo tiến trình nền được sinh ra bởi chương trình của tôi bị giết khi quá trình của tôi chấm dứt?

Có cách nào để đảm bảo rằng quá trình con kết thúc mà không yêu cầu quy trình con biết về quy trình gốc không? Tôi muốn một giải pháp trong mã được quản lý, nhưng nếu không có một trong tôi có thể PInvoke.

Chỉnh sửa: Chuyển PID có vẻ như là một giải pháp mạnh mẽ hơn, nhưng vì sự tò mò, nếu quy trình con không phải là mã của tôi nhưng một số exe mà tôi không kiểm soát được? Có cách nào để bảo vệ chống lại việc có thể tạo ra các tiến trình con mồ côi không?

Trả lời

7

Nếu quá trình con là mã của riêng bạn, bạn có thể chuyển mã PID của quy trình gốc khi bạn khởi chạy. Quy trình con sau đó có thể tìm nạp quy trình với Process.GetProcessById và đăng ký sự kiện Exited của nó với trình xử lý sẽ tắt quá trình còn lại của quá trình (con). Lưu ý rằng bạn cần đặt thuộc tính EnableRaisingEvents trên quy trình thành true.

3

Thuật ngữ chung cho quy trình con như vậy ở dạng orphan process. Xem bài viết được liên kết cho một số giải pháp có thể có.

0

Vượt qua id quá trình gốc dưới dạng thông số dòng lệnh cho quá trình con.

Trong quá trình sử dụng con được trình bởi id và đăng ký với nó là sự kiện Exit hoặc tạo một thread và gọi điện để Process.WaitForExit

5

Nếu quá trình đứa trẻ không phải là mã riêng của bạn, bạn có thể sử dụng mã này để tìm và tiêu diệt tất cả các tiến trình con:

using System; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 

namespace Util { 
    public static class ProcessExtensions { 
     public static void KillDescendants(this Process processToNotKillYet) { 
      foreach (var eachProcess in Process.GetProcesses()) { 
       if (eachProcess.ParentPid() == processToNotKillYet.Id) { 
        eachProcess.KillTree(); 
       } 
      } 
     } 

     public static void KillTree(this Process processToKill) { 
      processToKill.KillDescendants(); 
      processToKill.Kill(); 
     } 

     public static PROCESS_BASIC_INFORMATION Info(this Process process) { 
      var processInfo = new PROCESS_BASIC_INFORMATION(); 
      try { 
       uint bytesWritten; 
       NtQueryInformationProcess(process.Handle, 
              0, 
              ref processInfo, 
              (uint)Marshal.SizeOf(processInfo), 
              out bytesWritten); // == 0 is OK 
      } 
      catch (Win32Exception e) { 
       if (!e.Message.Equals("Access is denied")) throw; 
      } 

      return processInfo; 
     } 

     public static int ParentPid(this Process process) { 
      return process.Info().ParentPid; 
     } 

     [DllImport("ntdll.dll")] 
     private static extern int NtQueryInformationProcess(
      IntPtr hProcess, 
      int processInformationClass /* 0 */, 
      ref PROCESS_BASIC_INFORMATION processBasicInformation, 
      uint processInformationLength, 
      out uint returnLength); 

     [StructLayout(LayoutKind.Sequential)] 
     public struct PROCESS_BASIC_INFORMATION { 
      public int ExitStatus; 
      public int PebBaseAddress; 
      public int AffinityMask; 
      public int BasePriority; 
      public int Pid; 
      public int ParentPid; 
     } 
    } 
} 
+0

Check-out cũng câu trả lời này cho một số mã ngắn với một cách tiếp cận khác nhau: http://stackoverflow.com/a/7189381/177710. – Oliver

1

Dưới đây là một mã nguồn cho một ứng dụng tiện ích nhỏ tôi đã xây dựng (nó được dựa trên giải pháp Alan Hensel, mà tôi tìm thấy khá hữu ích).

Nó được gọi là ChildrenProcessKiller và nó là một watcher cho phép để giết tất cả con cháu quá trình của một quá trình cha mẹ đưa ra khi các lối ra quá trình cha mẹ (thậm chí nếu quá trình cha mẹ bị treo)

Cách sử dụng:

ChildrenProcessKiller.exe parentProcessId 

Cảnh báo: mã này được cung cấp "như là", và nó có thể giết trẻ nhỏ ;-)

ChildrenProcessKiller.cs

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 

namespace ChildrenProcessKiller 
{ 
    static class ChildrenProcessKiller 
    { 
    [STAThread] 
    static void Main(string[] args) 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 

     string message = "This is a watcher that enables to kill all descendants process of a given parent process\n"; 
     message += "when the parent process exits (even if the parent process crashes) \n\n"; 
     message += "Usage : " + Application.ExecutablePath + " parentProcessId"; 

     if (args.Length != 1) 
     { 
     MessageBox.Show(message); 
     System.Environment.Exit(1); 
     } 

     int parentProcessId; 
     if (!Int32.TryParse(args[0], out parentProcessId)) 
     { 
     MessageBox.Show(message); 
     System.Environment.Exit(1); 
     } 

     try 
     { 
     mParentProcess = Process.GetProcessById(parentProcessId); 
     } 
     catch (System.ArgumentException ex) 
     { 
     //Parent process cannot be found! 
     System.Environment.Exit(2); 
     } 
     Run(); 
    } 

    private static List<Process> mChildrenProcesses; 
    private static Process mParentProcess; 

    private static void Run() 
    { 
     int thisProcessId = Process.GetCurrentProcess().Id; 
     while (! mParentProcess.HasExited) 
     { 
     RefreshChildrenProcesses(); 
     System.Threading.Thread.Sleep(1000); 
     } 

     foreach (Process childProcess in mChildrenProcesses) 
     { 
     if ((!childProcess.HasExited) && (childProcess.Id != thisProcessId)) 
     { 
      KillGracefullyThenViolently(childProcess); 
     } 
     } 
    } 

    private static void KillGracefullyThenViolently(Process process) 
    { 
     if (process.HasExited) 
     return; 

     try 
     { 
     process.CloseMainWindow(); 
     } 
     catch (PlatformNotSupportedException) 
     {} 
     catch (InvalidOperationException) 
     {}//do nothing : this app is meant to be "unstoppable", unless the parent process has exited 

     for (int i = 0; i < 15; i++) 
     { 
     System.Threading.Thread.Sleep(100); 
     if (process.HasExited) 
      return; 
     } 

     try 
     { 
     process.Kill(); 
     } 
     catch (System.ComponentModel.Win32Exception) 
     {} 
     catch(NotSupportedException) 
     {} 
     catch(InvalidOperationException) 
     {} //same comment here 
    } 

    private static void RefreshChildrenProcesses() 
    { 
     if (mParentProcess.HasExited) 
     return; 
     List<Process> newChildren; 
     try 
     { 
     newChildren = Utils.ProcessTree.GetProcessDescendants(mParentProcess); 
     mChildrenProcesses = newChildren; 
     } 
     catch (System.Exception ex) 
     { 
     ; 
     } 
    } 


    } 
} 

ProcessTree.cs

using System; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Collections.Generic; 
using System.IO; 
using System.Windows.Forms; 

namespace Utils 
{ 
    public static class ProcessTree 
    { 

    public static List<Process> GetProcessDescendants(Process process) 
    { 
     List<Process> result = new List<Process>(); 
     foreach (Process eachProcess in Process.GetProcesses()) 
     { 
     if (ParentPid(eachProcess) == process.Id) 
     { 
      result.Add(eachProcess); 
     } 
     } 
     return result; 
    } 

    public static void KillDescendants(Process processToNotKillYet) 
    { 
     foreach (Process eachProcess in Process.GetProcesses()) 
     { 
     if (ParentPid(eachProcess) == processToNotKillYet.Id) 
     { 
      if (eachProcess.Id != Process.GetCurrentProcess().Id) 
      KillTree(eachProcess); 
     } 
     } 
    } 

    public static void KillTree(Process processToKill) 
    { 
     KillDescendants(processToKill); 
     processToKill.Kill(); 
    } 

    public static PROCESS_BASIC_INFORMATION Info(Process process) 
    { 
     PROCESS_BASIC_INFORMATION processInfo = new PROCESS_BASIC_INFORMATION(); 
     try 
     { 
     uint bytesWritten; 
     NtQueryInformationProcess(process.Handle, 
         0, 
         ref processInfo, 
         (uint)Marshal.SizeOf(processInfo), 
         out bytesWritten); // == 0 is OK 
     } 
     catch (Win32Exception e) 
     { 
     if (!e.Message.Equals("Access is denied")) throw; 
     } 

     return processInfo; 
    } 

    public static int ParentPid(Process process) 
    { 
     return Info(process).ParentPid; 
    } 

    [DllImport("ntdll.dll")] 
    private static extern int NtQueryInformationProcess(
     IntPtr hProcess, 
     int processInformationClass /* 0 */, 
     ref PROCESS_BASIC_INFORMATION processBasicInformation, 
     uint processInformationLength, 
     out uint returnLength); 

    [StructLayout(LayoutKind.Sequential)] 
    public struct PROCESS_BASIC_INFORMATION 
    { 
     public int ExitStatus; 
     public int PebBaseAddress; 
     public int AffinityMask; 
     public int BasePriority; 
     public int Pid; 
     public int ParentPid; 
    } 
    } 
} 
Các vấn đề liên quan