내 프로세스가 종료 될 때 내 프로그램에 의해 스폰 된 배경 프로세스가 사망 할 수있는 방법이 있습니까?
-
08-07-2019 - |
문제
기본적으로 자식 프로세스는 백그라운드에서 죽일 때까지 무기한으로 실행되며, 어떤 이유로 든 TaskManager를 통해 프로그램이 종료되면 정리하고 싶습니다.
현재는 시간이 오래 걸리고 있습니다 (Process.GetProcessesByName ( "ParentProcess"). count ()> 0) 루프 및 출구가 실행되지 않으면 종료하지만 꽤 부서지기 쉬운 것처럼 보이지만 Visual에서 디버거 아래에서 작동하기를 원한다면 스튜디오 "ParentProcess.vshost"또는 무언가를 추가해야합니다.
아동 프로세스가 부모 과정에 대해 알 수 있도록 아동 프로세스가 끝나지 않도록하는 방법이 있습니까? 관리자 코드에서 솔루션을 선호하지만 코드가 없으면 Pinvoke를 할 수 있습니다.
편집 : PID를 통과하는 것은 더 강력한 솔루션처럼 보이지만 호기심을 위해서는 어린이 프로세스가 내 코드가 아니라 통제 할 수없는 일부 EXE라면 어떨까요? 고아 아동 프로세스를 만들 가능성을 방지 할 수있는 방법이 있습니까?
해결책
자식 프로세스가 자신의 코드 인 경우, 출시시 부모 프로세스의 PID를 전달할 수 있습니다. 아동 과정은 프로세스를 가져올 수 있습니다 Process.GetProcessById
그리고 그것의 구독 Exited
나머지 (자식) 프로세스를 정상적으로 종료하는 핸들러가있는 이벤트. 설정해야합니다 EnableRaisingEvents
프로세스의 재산 true
.
다른 팁
자식 프로세스가 자신의 코드가 아닌 경우이 코드를 사용하여 모든 아동 프로세스를 찾아 죽일 수 있습니다.
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;
}
}
}
그러한 아동 프로세스에 대한 일반적인 용어는 고아 과정. 가능한 솔루션은 링크 된 기사를 참조하십시오.
여기에 제작 한 작은 유틸리티 앱의 소스 코드 (Alan Hensel 솔루션을 기반으로합니다. 매우 유용한 것으로 나타났습니다).
이를 childrenprocesskiller라고하며 부모 프로세스가 종료 될 때 (부모 프로세스가 충돌하더라도) 주어진 부모 프로세스의 모든 후손 프로세스를 죽일 수있는 감시자입니다.
용법 :
ChildrenProcessKiller.exe parentProcessId
경고 :이 코드는 "있는 그대로"제공되며 작은 아기를 죽일 수 있습니다 ;-)
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;
}
}
}
부모 프로세스 ID를 명령 줄 매개 변수로 전달하여 하위 프로세스로 전달하십시오.
아동 프로세스에서 ID에 의한 프로세스 받기 및 출구 이벤트를 구독하거나 스레드를 생성하고 프로세스를 호출합니다. waitforexit