콘솔 종료 C # 캡처
꽤 많은 스레드가 포함 된 콘솔 응용 프로그램이 있습니다. 특정 조건을 모니터링하고 참일 경우 프로그램을 종료하는 스레드가 있습니다. 이 종료는 언제든지 발생할 수 있습니다.
다른 모든 스레드를 정리하고 모든 파일 핸들과 연결을 제대로 닫을 수 있도록 프로그램이 닫힐 때 트리거 될 수있는 이벤트가 필요합니다. .NET 프레임 워크에 이미 빌드 된 것이 있는지 확실하지 않으므로 직접 작성하기 전에 묻습니다.
다음과 같은 이벤트가 있는지 궁금합니다.
MyConsoleProgram.OnExit += CleanupBeforeExit;
웹에서 코드를 어디에서 찾았는지 잘 모르겠지만 지금은 이전 프로젝트 중 하나에서 찾았습니다. 이렇게하면 콘솔에서 정리 코드를 수행 할 수 있습니다. 예를 들어 갑자기 닫히거나 종료로 인해 ...
[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)
{
switch (sig)
{
case CtrlType.CTRL_C_EVENT:
case CtrlType.CTRL_LOGOFF_EVENT:
case CtrlType.CTRL_SHUTDOWN_EVENT:
case CtrlType.CTRL_CLOSE_EVENT:
default:
return false;
}
}
static void Main(string[] args)
{
// Some biolerplate to react to close window event
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
...
}
최신 정보
의견을 확인하지 않는 사람들에게는이 특정 솔루션이 Windows 7 에서 잘 작동 하지 않는 것 같습니다 (또는 전혀) . 다음 스레드 는 이것에 대해 이야기합니다.
전체 작업 예제는 ctrl-c로 작업하고 X로 창을 닫고 종료합니다.
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 boilerplate 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..");
}
}
}
또한 확인 :
AppDomain.CurrentDomain.ProcessExit
스레드가 응용 프로그램을 직접 종료하는 것 같습니까? 애플리케이션이 종료되어야한다는 것을 알리기 위해 스레드가 메인 스레드에 신호를 보내는 것이 더 낫습니다.
이 신호를 받으면 메인 스레드는 다른 스레드를 완전히 종료하고 마지막으로 자신을 종료 할 수 있습니다.
비슷한 문제가 있었는데, 내 콘솔 앱이 중간에 하나의 선점 문이있는 무한 루프에서 실행될 것입니다. 내 해결책은 다음과 같습니다.
class Program
{
static int Main(string[] args)
{
// Init Code...
Console.CancelKeyPress += Console_CancelKeyPress; // Register the function to cancel event
// I do my stuffs
while ( true )
{
// Code ....
SomePreemptiveCall(); // The loop stucks here wating function to return
// Code ...
}
return 0; // Never comes here, but...
}
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("Exiting");
// Termitate what I have to terminate
Environment.Exit(-1);
}
}
WinForms 앱이 있습니다.
Application.ApplicationExit += CleanupBeforeExit;
콘솔 앱의 경우
AppDomain.CurrentDomain.DomainUnload += CleanupBeforeExit;
그러나 어떤 시점에서 호출되는지 또는 현재 도메인 내에서 작동하는지 확실하지 않습니다. 나는 그렇지 않다고 생각한다.
ZeroKelvin의 답변은 Windows 10 x64, .NET 4.6 콘솔 앱에서 작동합니다. CtrlType 열거 형을 다룰 필요가없는 사람들을 위해 다음은 프레임 워크의 종료에 연결하는 매우 간단한 방법입니다.
class Program
{
private delegate bool ConsoleCtrlHandlerDelegate(int sig);
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandlerDelegate handler, bool add);
static ConsoleCtrlHandlerDelegate _consoleCtrlHandler;
static void Main(string[] args)
{
_consoleCtrlHandler += s =>
{
//DoCustomShutdownStuff();
return false;
};
SetConsoleCtrlHandler(_consoleCtrlHandler, true);
}
}
핸들러에서 FALSE를 반환하면 프레임 워크에 제어 신호를 "처리"하지 않고 있으며이 프로세스의 핸들러 목록에있는 다음 핸들러 함수가 사용됩니다. TRUE를 반환하는 처리기가 없으면 기본 처리기가 호출됩니다.
사용자가 로그 오프 또는 종료를 수행하면 콜백이 Windows에서 호출되지 않고 대신 즉시 종료됩니다.
Visual Studio 2015 + Windows 10
- 정리 허용
- 단일 인스턴스 앱
- 일부 금도금
암호:
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
namespace YourNamespace
{
class Program
{
// if you want to allow only one instance otherwise remove the next line
static Mutex mutex = new Mutex(false, "YOURGUID-YOURGUID-YOURGUID-YO");
static ManualResetEvent run = new ManualResetEvent(true);
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler exitHandler;
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 ExitHandler(CtrlType sig)
{
Console.WriteLine("Shutting down: " + sig.ToString());
run.Reset();
Thread.Sleep(2000);
return false; // If the function handles the control signal, it should return TRUE. If it returns FALSE, the next handler function in the list of handlers for this process is used (from MSDN).
}
static void Main(string[] args)
{
// if you want to allow only one instance otherwise remove the next 4 lines
if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false))
{
return; // singleton application already started
}
exitHandler += new EventHandler(ExitHandler);
SetConsoleCtrlHandler(exitHandler, true);
try
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.Black;
Console.Clear();
Console.SetBufferSize(Console.BufferWidth, 1024);
Console.Title = "Your Console Title - XYZ";
// start your threads here
Thread thread1 = new Thread(new ThreadStart(ThreadFunc1));
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(ThreadFunc2));
thread2.IsBackground = true; // a background thread
thread2.Start();
while (run.WaitOne(0))
{
Thread.Sleep(100);
}
// do thread syncs here signal them the end so they can clean up or use the manual reset event in them or abort them
thread1.Abort();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("fail: ");
Console.ForegroundColor = ConsoleColor.Black;
Console.WriteLine(ex.Message);
if (ex.InnerException != null)
{
Console.WriteLine("Inner: " + ex.InnerException.Message);
}
}
finally
{
// do app cleanup here
// if you want to allow only one instance otherwise remove the next line
mutex.ReleaseMutex();
// remove this after testing
Console.Beep(5000, 100);
}
}
public static void ThreadFunc1()
{
Console.Write("> ");
while ((line = Console.ReadLine()) != null)
{
if (line == "command 1")
{
}
else if (line == "command 1")
{
}
else if (line == "?")
{
}
Console.Write("> ");
}
}
public static void ThreadFunc2()
{
while (run.WaitOne(0))
{
Thread.Sleep(100);
}
// do thread cleanup here
Console.Beep();
}
}
}
The link mentioned above by Charle B in comment to flq
Deep down says:
SetConsoleCtrlHandler won't work on windows7 if you link to user32
Some where else in the thread it is suggested to crate a hidden window. So I create a winform and in onload I attached to console and execute original Main. And then SetConsoleCtrlHandle works fine (SetConsoleCtrlHandle is called as suggested by flq)
public partial class App3DummyForm : Form
{
private readonly string[] _args;
public App3DummyForm(string[] args)
{
_args = args;
InitializeComponent();
}
private void App3DummyForm_Load(object sender, EventArgs e)
{
AllocConsole();
App3.Program.OriginalMain(_args);
}
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
}
For those interested in VB.net. (I searched the internet and couldn't find an equivalent for it) Here it is translated into vb.net.
<DllImport("kernel32")> _
Private Function SetConsoleCtrlHandler(ByVal HandlerRoutine As HandlerDelegate, ByVal Add As Boolean) As Boolean
End Function
Private _handler As HandlerDelegate
Private Delegate Function HandlerDelegate(ByVal dwControlType As ControlEventType) As Boolean
Private Function ControlHandler(ByVal controlEvent As ControlEventType) As Boolean
Select Case controlEvent
Case ControlEventType.CtrlCEvent, ControlEventType.CtrlCloseEvent
Console.WriteLine("Closing...")
Return True
Case ControlEventType.CtrlLogoffEvent, ControlEventType.CtrlBreakEvent, ControlEventType.CtrlShutdownEvent
Console.WriteLine("Shutdown Detected")
Return False
End Select
End Function
Sub Main()
Try
_handler = New HandlerDelegate(AddressOf ControlHandler)
SetConsoleCtrlHandler(_handler, True)
.....
End Sub
참고URL : https://stackoverflow.com/questions/474679/capture-console-exit-c-sharp
'Programing' 카테고리의 다른 글
아무것도 반환하지 않는 함수를 만드는 방법 (0) | 2020.09.10 |
---|---|
웹 사이트에서 파비콘을 만드는 가장 좋은 방법은 무엇입니까? (0) | 2020.09.10 |
Rails Console과 동등한 Phoenix가 있습니까? (0) | 2020.09.10 |
서비스에 애플리케이션 (비 인프라) 엔드 포인트가 없습니다. (0) | 2020.09.10 |
배치 파일에는 변수에 대한 외부 파일이 포함됩니다. (0) | 2020.09.10 |