2011-04-20 7 views
2

종료 할 때 리소스를 정리해야하는 .NET 콘솔 앱에서 작업하고 있습니다. 내가 겪고있는 문제는 cmd 부모가 [X] 콘솔 창을 통해, 작업 관리자/프로세스 탐색기를 통해 또는 프로그래밍 방식으로 WM_CLOSE를 통해 닫히는 경우 알림이 표시되지 않는다는 것입니다. 내가 살 수 있는와 함께 살 수 킬 프로세스 작업 관리자에서. 또는 ProcExp. 부모 콘솔의 WM_CLOSE는 처리가 완료되기 전에이 응용 프로그램이 종료 될 가능성이 가장 높습니다. 나는 콘솔에서 CTRL + C를 보내거나 응용 프로그램이 중단 끝날 때부모 프로세스 종료 확인 방법?

AppDomain.CurrentDomain.ProcessExit += CurrentDomainProcessExit; 
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException; 
Console.CancelKeyPress += ConsoleCancelKeyPress; 
Application.ApplicationExit += ApplicationApplicationExit; 

Process parentProcess = ProcessInfo.GetParentProcess(
    Process.GetCurrentProcess()); 
parentProcess.Disposed += ParentDisposed; 
parentProcess.Exited += ParentExited; 

Process grandParentProcess = ProcessInfo.GetParentProcess(parentProcess); 
grandParentProcess.Disposed += GrandParentDisposed; 
grandParentProcess.Exited += GrandParentExited; 

이러한 이벤트가 제대로 불 :

는 여기에 지금까지 등록을 시도한 이벤트입니다. 하지만 부모 앱 (cmd 콘솔)을 닫을 때 실행되는 프로그램은 없습니다. (부모/조부모 프로세스는 CLR이 아니므로 Disposed/Exited 이벤트를받을 수 있을지 잘 모르겠다. 어둡기 만 한 장면입니다.) 일부 pInvoke 항목을 살펴 봤지만 차라리 내려 가지 않을 것입니다. 그 길 .NET이 옵션이라면.

이러한 상황에서 시스템 종료를 감지하고 처리하는 방법이 있습니까? 나는 모든 .NET, pInvoke/Win32/C/C++ 솔루션에 개방되어 있습니다. (기본적으로 Windows 플랫폼에서 수행 할 수 있습니다.)

감사합니다.

P. .NET 2.0에서 계속 작동하므로 .NET 3.0에서 도입 된 아무것도 사용할 수 없습니다.

+0

어떤 종류의 자원을 정리해야하며 어떤 종류의 정리가 필요합니까? –

+0

부모님은 콘솔 앱이라고 말씀 하셨지만 WM_CLOSE에 대해 언급하셨습니다. 부모가 콘솔 앱입니까 (이 경우 창이 없음) 또는 창 응용 프로그램입니까? (이 경우 WM_CLOSE를 보낼 수 있습니다)? – Gabe

+0

@ 존 : 프로세스가 조기에 중단 된 경우 중지해야하는 다른 작업을 실행합니다. 그렇지 않으면 하위 작업이 고아가되고 스폰 프로세스없이 완료됩니다. –

답변

2

최상의 방법은 P/Invoke를 사용하는 것입니다. Windows API 함수 SetConsoleCtrlHandler()이 예상 한대로 작동 할 수 있습니다.

아래의 샘플 코드는 here (MSDN에서 사용 가능한 유사한 코드, here)에서 도난당했습니다. 에 관계없이 프로세스가 닷넷, 원시, 또는 무엇인지는 ProcessEnableRaisingEvents = true을 설정할 때마다

class Program 
{ 
    [DllImport("Kernel32")] 
    public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add); 

    // A delegate type to be used as the handler routine 
    // for SetConsoleCtrlHandler. 
    public delegate bool HandlerRoutine(CtrlTypes CtrlType); 

    // An enumerated type for the control messages 
    // sent to the handler routine. 
    public enum CtrlTypes 
    { 
     CTRL_C_EVENT = 0, 
     CTRL_BREAK_EVENT, 
     CTRL_CLOSE_EVENT, 
     CTRL_LOGOFF_EVENT = 5, 
     CTRL_SHUTDOWN_EVENT 
    } 

    private static bool ConsoleCtrlCheck(CtrlTypes ctrlType) 
    { 
     // Put your own handler here 
     return true; 
    } 

    static void Main(string[] args) 
    { 
     SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true); 
    } 
} 
+0

이것은 좋은 대답입니다. 불행히도 부모 응용 프로그램의 코드를 살펴볼 때이 메서드는 이미 사용 중이며 이벤트가 갇혀서 내 응용 프로그램에 전달되지 않습니다. 나는 C 계획을 가지고이 문제를 다루기 위해 IPC 메커니즘을 구현해야 할 것이다. –

2

Exited 이벤트가 발생한다. Exited 이벤트가 발생하지 않고 실제로 Process 종료가 표시되는 경우 작은 재생 시나리오를 게시 할 수 있습니까?

또한 Disposed 이벤트는 시나리오에서 쓸모가 없습니다. 프로세스의 Process 개체 인스턴스에서 Dispose()을 호출 할 때만 발생하며 개체가 참조하는 OS 프로세스 내에서 발생하는 작업과 아무런 관련이 없습니다.

0

예제의 ProcessInfo 클래스가 System.Web 네임 스페이스의 일부일 수 있습니다. MSDN 견적에 "ASP.Net 프로세스 모델에서 실행중인 ASP.Net 작업자 프로세스에 대한 정보가 반환됩니다." 이렇게하면 명령 줄 응용 프로그램에별로 도움이되지 않을 것 같습니다.

System.Management 네임 스페이스를 통해 WMI를 사용해야합니다. 다음 샘플에서는 트릭을 수행하고 현재 프로세스의 바로 위 부모에 대한 System.Diagnostics.Process 개체를 가져와야합니다. 이 예제에서는 Process.WaitForExit() 메서드를 사용하지만 이벤트 처리기를 연결하면 잘 작동합니다.

그러나 특히 콘솔 응용 프로그램에 대한 이야기 ​​이후에 즉각적인 상위 프로세스가 이 아니고이 아니어야 현재 프로세스를 실제로 생성 한 프로세스임을 유의해야합니다.프로세스 A가 ProcessStartInfo 프로세스 A가 ProcessStartInfoUseShellExecute=true을 지정하여 프로세스 B (콘솔 응용 프로그램)을 생성합니다 경우, 그러나 B의 바로 위 부모가 될 것보다는, UseShellExecute=false를 지정하여 직접 처리 콘솔 응용 프로그램의 B를 생성합니다 경우 하지 수, 다음의 뜻을 처리 프로세스 B의 직계 부모 : A와 B 사이에 중간 프로세스 (cmd.exe)가있을 것입니다. * .cmd 배치 파일이나 PowerShell 코드를 사용하는 경우 더 복잡 할 수 있습니다.

관심있는 부모를 찾으려면 프로세스 트리를 더 많이 실행해야 할 수도 있습니다.

또한 부모 프로세스를 생성하지 않았기 때문에 부모 프로세스의 조건 (종료) 코드가 완료된 후에도 액세스 할 수 없습니다. 부모 프로세스의 ExitCode 속성에 액세스하려고하면 잘못된 연산 예외가 throw됩니다.

using System; 
using System.Collections; 
using System.Diagnostics; 
using System.Management; 

namespace WaitOnParentProcessSample 
{ 
    class Program 
    { 

     static int Main(string[] argv) 
     { 
      using (Process parentProcess = GetParentProcess()) 
      { 
       Console.WriteLine("Waiting for parent process (pid:{0}) to exit..." , parentProcess.Id); 
       parentProcess.WaitForExit(); 
       Console.WriteLine("Parent Process Has exited. Condition code cannot be determined"); 
      } 

      return 0; 
     } 

     private static Process GetParentProcess() 
     { 
      Process parentProcess = null; 

      using (Process currentProcess = Process.GetCurrentProcess()) 
      { 
       string  filter = string.Format("ProcessId={0}" , currentProcess.Id); 
       SelectQuery query = new SelectQuery("Win32_Process" , filter); 

       using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query)) 
       using (ManagementObjectCollection results = searcher.Get()) 
       { 

        if (results.Count>0) 
        { 
         if (results.Count>1) 
          throw new InvalidOperationException(); 
         IEnumerator  resultEnumerator = results.GetEnumerator(); 
         bool    fMoved   = resultEnumerator.MoveNext(); 

         using (ManagementObject wmiProcess = (ManagementObject)resultEnumerator.Current) 
         { 
          PropertyData parentProcessId = wmiProcess.Properties["ParentProcessId"]; 
          uint   pid = (uint)parentProcessId.Value; 

          parentProcess=Process.GetProcessById((int)pid); 

         } 

        } 

       } 

      } 

      return parentProcess; 

     } 

    } 

} 
+0

흥미로운 생각이지만 이러한 프로세스는 다른 프로세스를 호출하는 서비스 또는 콘솔 앱입니다. IIS는 전혀 관련이 없습니다. –

+0

'Process parentProcess = ProcessInfo.GetParentProcess (Process.GetCurrentProcess()); '에서 참조하고있는 실제'ProcessInfo' 클래스는 무엇입니까? 자신 만의 커스텀 코드가 아니라면 .Net 프레임 워크에서 그 이름의 유일한 클래스는'System.Web.ProcessInfo'이며 Asp.Net 작업자 프로세스에만 해당됩니다. 그러나 위의 예제 코드에서와 같이 WMI를 쿼리하면 부모 프로세스가 생성됩니다. –

+0

맞습니다. 그것은 사내 유틸리티 클래스입니다. 우리가 System.Web 네임 스페이스를 사용하지 않기 때문에 명명 충돌은 결코 문제가되지 않습니다. 아직도, 나는 그것을 ProcessUtil 또는 미래의 어떤 혼란을 피하기 위해 그러한 이름으로 바꿀 것이라고 생각한다. –

관련 문제