Gibt es in .NET eine Methode, z. B. ein Ereignis, um zu erkennen, wann eine Konsolenanwendung beendet wird? Ich muss einige Threads und COM-Objekte bereinigen.
Ich führe eine Nachrichtenschleife ohne Formular über die Konsolenanwendung aus. Eine DCOM-Komponente, die ich verwende, scheint zu erfordern, dass die Anwendung Nachrichten meldet.
Ich habe versucht, Process.GetCurrentProcess.Exited und Process.GetCurrentProcess.Disposed einen Handler hinzuzufügen.
Ich habe auch versucht, Application.ApplicationExit- und Application.ThreadExit-Ereignissen einen Handler hinzuzufügen, aber sie werden nicht ausgelöst. Vielleicht liegt das daran, dass ich kein Formular verwende.
.net
console-application
complexity-theory
user79755
quelle
quelle
Antworten:
Sie können das
ProcessExit
Ereignis desAppDomain
: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"); } }
Aktualisieren
Hier ist ein vollständiges Beispielprogramm mit einer leeren "Nachrichtenpumpe", die in einem separaten Thread ausgeführt wird und es dem Benutzer ermöglicht, einen Beendigungsbefehl in die Konsole einzugeben, um die Anwendung ordnungsgemäß zu schließen. Nach der Schleife in MessagePump möchten Sie wahrscheinlich die vom Thread verwendeten Ressourcen auf nette Weise bereinigen. Dies ist aus mehreren Gründen besser als in ProcessExit:
Hier ist der Code:
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"); } }
quelle
Hier ist eine vollständige, sehr einfache .Net-Lösung, die in allen Windows-Versionen funktioniert. Fügen Sie es einfach in ein neues Projekt ein, führen Sie es aus und versuchen Sie STRG-C, um zu sehen, wie es damit umgeht:
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.."); } } }
quelle
Die Anwendung ist ein Server, der einfach ausgeführt wird, bis das System heruntergefahren wird oder Strg + C empfängt oder das Konsolenfenster geschlossen wird.
Aufgrund des außergewöhnlichen Charakters der Anwendung ist es nicht möglich, "ordnungsgemäß" zu beenden. (Es kann sein, dass ich eine andere Anwendung codieren könnte, die eine Meldung zum "Herunterfahren des Servers" sendet, dies jedoch für eine Anwendung übertrieben und für bestimmte Umstände, z. B. wenn der Server (tatsächliches Betriebssystem) tatsächlich heruntergefahren wird, immer noch unzureichend ist.)
Aufgrund dieser Umstände habe ich einen " ConsoleCtrlHandler " hinzugefügt, in dem ich meine Threads stoppe und meine COM-Objekte bereinige usw.
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
Dieses Setup scheint perfekt zu funktionieren. Hier ist ein Link zu einem C # -Code für dasselbe.
quelle
Für den Fall STRG + C können Sie Folgendes verwenden:
// 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); }
quelle
Können Sie die WM_QUIT-Nachricht nicht verwenden, wenn Sie eine Konsolenanwendung verwenden und Nachrichten pumpen?
quelle
Als gutes Beispiel kann es sich lohnen, zu diesem Projekt zu navigieren und zu sehen, wie das Beenden von Prozessen grammatikalisch oder in diesem hier gefundenen Snippet von VM behandelt wird
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; }
quelle