IT TIP

.NET 콘솔 응용 프로그램 종료 이벤트

itqueen 2020. 11. 20. 17:32
반응형

.NET 콘솔 응용 프로그램 종료 이벤트


.NET에서 콘솔 응용 프로그램이 종료되는시기를 감지하는 이벤트와 같은 방법이 있습니까? 일부 스레드와 COM 개체를 정리해야합니다.

콘솔 응용 프로그램에서 양식없이 메시지 루프를 실행하고 있습니다. 내가 사용하는 DCOM 구성 요소는 응용 프로그램 펌프 메시지를 요구하는 것 같습니다.

Process.GetCurrentProcess.Exited 및 Process.GetCurrentProcess.Disposed에 처리기를 추가하려고했습니다.

또한 Application.ApplicationExit 및 Application.ThreadExit 이벤트에 처리기를 추가하려고 시도했지만 실행되지 않습니다. 아마도 양식을 사용하지 않기 때문일 것입니다.


다음 ProcessExit이벤트를 사용할 수 있습니다 AppDomain.

class Program
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);           
        // do some work

    }

    static void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        Console.WriteLine("exit");
    }
}

최신 정보

다음은 별도의 스레드에서 실행되는 빈 "메시지 펌프"가 포함 된 전체 예제 프로그램으로, 사용자가 콘솔에 종료 명령을 입력하여 응용 프로그램을 정상적으로 종료 할 수 있도록합니다. MessagePump의 루프 후에 스레드에서 사용하는 리소스를 좋은 방식으로 정리하고 싶을 것입니다. 다음과 같은 몇 가지 이유로 ProcessExit보다 거기에서 수행하는 것이 좋습니다.

  • 크로스 스레딩 문제를 피하십시오. MessagePump 스레드에서 외부 COM 개체가 생성 된 경우 여기에서 처리하는 것이 더 쉽습니다.
  • ProcessExit에는 시간 제한 (기본적으로 3 초)이 있으므로 정리하는 데 시간이 많이 걸리는 경우 해당 이벤트 처리기 내에서 수행하면 실패 할 수 있습니다.

다음은 코드입니다.

class Program
{
    private static bool _quitRequested = false;
    private static object _syncLock = new object();
    private static AutoResetEvent _waitHandle = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
        // start the message pumping thread
        Thread msgThread = new Thread(MessagePump);
        msgThread.Start();
        // read input to detect "quit" command
        string command = string.Empty;
        do
        {
            command = Console.ReadLine();
        } while (!command.Equals("quit", StringComparison.InvariantCultureIgnoreCase));
        // signal that we want to quit
        SetQuitRequested();
        // wait until the message pump says it's done
        _waitHandle.WaitOne();
        // perform any additional cleanup, logging or whatever
    }

    private static void SetQuitRequested()
    {
        lock (_syncLock)
        {
            _quitRequested = true;
        }
    }

    private static void MessagePump()
    {
        do
        {
            // act on messages
        } while (!_quitRequested);
        _waitHandle.Set();
    }

    static void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        Console.WriteLine("exit");
    }
}

다음은 모든 버전의 Windows에서 작동하는 완전하고 매우 간단한 .Net 솔루션입니다. 새 프로젝트에 붙여넣고 실행 한 다음 CTRL-C를 사용하여 처리 방법을 확인하면됩니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace TestTrapCtrlC{
    public class Program{
        static bool exitSystem = false;

        #region Trap application termination
        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

        private delegate bool EventHandler(CtrlType sig);
        static EventHandler _handler;

        enum CtrlType {
         CTRL_C_EVENT = 0,
         CTRL_BREAK_EVENT = 1,
         CTRL_CLOSE_EVENT = 2,
         CTRL_LOGOFF_EVENT = 5,
         CTRL_SHUTDOWN_EVENT = 6
         }

        private static bool Handler(CtrlType sig) {
            Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");

            //do your cleanup here
            Thread.Sleep(5000); //simulate some cleanup delay

            Console.WriteLine("Cleanup complete");

            //allow main to run off
             exitSystem = true;

            //shutdown right away so there are no lingering threads
            Environment.Exit(-1);

            return true;
        }
        #endregion

        static void Main(string[] args) {
            // Some biolerplate to react to close window event, CTRL-C, kill, etc
            _handler += new EventHandler(Handler);
            SetConsoleCtrlHandler(_handler, true);

            //start your multi threaded program here
            Program p = new Program();
            p.Start();

            //hold the console so it doesn’t run off the end
            while(!exitSystem) {
                Thread.Sleep(500);
            }
        }

        public void Start() {
            // start a thread and start doing some processing
            Console.WriteLine("Thread started, processing..");
        }
    }
 }

응용 프로그램은 시스템이 종료되거나 Ctrl + C를 받거나 콘솔 창이 닫힐 때까지 단순히 실행되는 서버입니다.

응용 프로그램의 비정상적인 특성으로 인해 "정상적으로"종료하는 것은 불가능합니다. ( "서버 종료"메시지를 보내는 다른 응용 프로그램을 코딩 할 수 있지만 한 응용 프로그램에 대해서는 과도하고 서버 (실제 OS)가 실제로 종료 될 때와 같은 특정 상황에서는 여전히 불충분합니다.)

이러한 상황 때문에 스레드를 중지하고 COM 개체 등을 정리 하는 " ConsoleCtrlHandler "를 추가했습니다 .


Public Declare Auto Function SetConsoleCtrlHandler Lib "kernel32.dll" (ByVal Handler As HandlerRoutine, ByVal Add As Boolean) As Boolean

Public Delegate Function HandlerRoutine(ByVal CtrlType As CtrlTypes) As Boolean

Public Enum CtrlTypes
  CTRL_C_EVENT = 0
  CTRL_BREAK_EVENT
  CTRL_CLOSE_EVENT
  CTRL_LOGOFF_EVENT = 5
  CTRL_SHUTDOWN_EVENT
End Enum

Public Function ControlHandler(ByVal ctrlType As CtrlTypes) As Boolean
.
.clean up code here
.
End Function

Public Sub Main()
.
.
.
SetConsoleCtrlHandler(New HandlerRoutine(AddressOf ControlHandler), True)
.
.
End Sub

이 설정은 완벽하게 작동하는 것 같습니다. 다음은 같은 것에 대한 일부 C # 코드에 대한 링크 입니다.


CTRL + C 케이스의 경우 다음을 사용할 수 있습니다.

// Tell the system console to handle CTRL+C by calling our method that
// gracefully shuts down.
Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);


static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
            Console.WriteLine("Shutting down...");
            // Cleanup here
            System.Threading.Thread.Sleep(750);
}

If you are using a console application and you are pumping messages, can't you use the WM_QUIT message?


As a good example may be worth it to navigate to this project and see how to handle exiting processes grammatically or in this snippet from VM found in here

                ConsoleOutputStream = new ObservableCollection<string>();

                var startInfo = new ProcessStartInfo(FilePath)
                {
                    WorkingDirectory = RootFolderPath,
                    Arguments = StartingArguments,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };
                ConsoleProcess = new Process {StartInfo = startInfo};

                ConsoleProcess.EnableRaisingEvents = true;

                ConsoleProcess.OutputDataReceived += (sender, args) =>
                {
                    App.Current.Dispatcher.Invoke((System.Action) delegate
                    {
                        ConsoleOutputStream.Insert(0, args.Data);
                        //ConsoleOutputStream.Add(args.Data);
                    });
                };
                ConsoleProcess.Exited += (sender, args) =>
                {
                    InProgress = false;
                };

                ConsoleProcess.Start();
                ConsoleProcess.BeginOutputReadLine();
        }
    }

    private void RegisterProcessWatcher()
    {
        startWatch = new ManagementEventWatcher(
            new WqlEventQuery($"SELECT * FROM Win32_ProcessStartTrace where ProcessName = '{FileName}'"));
        startWatch.EventArrived += new EventArrivedEventHandler(startProcessWatch_EventArrived);

        stopWatch = new ManagementEventWatcher(
            new WqlEventQuery($"SELECT * FROM Win32_ProcessStopTrace where ProcessName = '{FileName}'"));
        stopWatch.EventArrived += new EventArrivedEventHandler(stopProcessWatch_EventArrived);
    }

    private void stopProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
    {
        InProgress = false;
    }

    private void startProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
    {
        InProgress = true;
    }

참고URL : https://stackoverflow.com/questions/1119841/net-console-application-exit-event

반응형