Capture console exit C#
Solution 1
I am not sure where I found the code on the web, but I found it now in one of my old projects. This will allow you to do cleanup code in your console, e.g. when it is abruptly closed or due to a shutdown...
[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);
...
}
Update
For those not checking the comments it seems that this particular solution does not work well (or at all) on Windows 7. The following thread talks about this
Solution 2
Full working example, works with ctrl-c, closing the windows with X and kill:
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..");
}
}
}
Solution 3
Check also:
AppDomain.CurrentDomain.ProcessExit
Solution 4
I've had a similar problem, just my console App would be running in infinite loop with one preemptive statement on middle. Here is my solution:
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);
}
}
Solution 5
ZeroKelvin's answer works in Windows 10 x64, .NET 4.6 console app. For those who do not need to deal with the CtrlType enum, here is a really simple way to hook into the framework's shutdown:
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);
}
}
Returning FALSE from the handler tells the framework that we are not "handling" the control signal, and the next handler function in the list of handlers for this process is used. If none of the handlers returns TRUE, the default handler is called.
Note that when the user performs a logoff or shutdown, the callback is not called by Windows but is instead terminated immediately.
maljee
Updated on July 08, 2022Comments
-
maljee almost 2 years
I have a console application that contains quite a lot of threads. There are threads that monitor certain conditions and terminate the program if they are true. This termination can happen at any time.
I need an event that can be triggered when the program is closing so that I can cleanup all of the other threads and close all file handles and connections properly. I'm not sure if there is one already built into the .NET framework, so I'm asking before I write my own.
I was wondering if there was an event along the lines of:
MyConsoleProgram.OnExit += CleanupBeforeExit;
-
Randolpho over 15 yearsI have to agree with this answer. Forcing application exit and then trying to clean up afterward isn't he way to go. Control your application, Noit. Don't let it control you.
-
maljee over 15 yearsA thread spawned by me directly isn't necessarily the only thing that can close my application. Ctrl-C and the "close button" are other ways that it can end. The code posted by Frank, after minor modifications, fits perfectly.
-
Rob Parker about 15 yearsThe help docs for DomainUnload say "The EventHandler delegate for this event can perform any termination activities before the application domain is unloaded." So it sounds like it does work within the current domain. However, it may not work for his need because his threads may keep the domain up.
-
ingh.am about 14 yearsCan you use this to cancel the exit? Other than for when it's shutting down!
-
flq about 14 yearsjames, I have no idea but the Handler signature returns a bool, so I'd try out what happens when you return true/false
-
Cipi about 14 yearsThis works great, only
bool Handler()
mustreturn false;
(it returns nothing in the code) so it would work. If it returns true, windows prompts "Terminate Process Now" dialog. =D -
CharlesB over 13 yearsIt looks like this solution does not work with Windows 7 for shutdown event, see social.msdn.microsoft.com/Forums/en/windowscompatibility/thread/…
-
Maxim over 13 yearsBe aware that if you put a breakpoint in the 'Handler' method it will throw a NullReferenceException. Checked in VS2010, Windows 7.
-
flq over 13 yearsThat's awesome, Charles, and shocking...looks like this answer is slowly expiring, and I can't quite see an alternative :/
-
dko over 13 yearsThis doesn't work in Windows 7 at all, Unless I converted it wrong to vb.net Although I wasn't ever able to properly translate the _handler part of it
-
Zing- over 12 years
-
Kit10 over 11 yearsThis only appears to catch exits from return or Environment.Exit, it does not catch CTRL+C, CTRL+Break, nor the actual close button on the console.
-
Kit10 over 11 yearsThis only handles CTRL+C and CTRL+Close, it doesn't catch exists via returning, Environment.Exit nor clicking the close button.
-
BrainSlugs83 over 10 yearsThis worked great for me on Windows 7 (64-bit). Not sure why everyone's saying it doesn't. The only major modifications I made was to get rid of the enum and switch statement, and to "return false" from the method -- I do all my cleanup in the body of the method.
-
Acaz Souza over 9 yearsThis code is not fired if you use End Process in Task Manager.
-
Cardin over 9 yearsTried it in Win7 using .NET 4.5, it does fire even if closed via Task Manager.
-
Marcus Mangelsdorf over 8 yearsPossible source: MSDN forums
-
Mike Keskinov over 7 yearsActually this doesn't work. I have multi-window WFP app and I use console (
AllocConsole
as in your example) to show some additional information. The problem is that the whole app (all Windows) get closed if user clicks on the (X) on Console Window. TheSetConsoleCtrlHandler
works, but the app halts anyway before any code in the handler executed (I see breakpoints fired and right then the app halts). -
Mike Keskinov over 7 yearsBut I found solution which works for me -- I simple DISABLED close button. See: stackoverflow.com/questions/6052992/…
-
Antonios Hadjigeorgalis about 7 yearsI tested this on windows 7 with everything commented out of
Handler
except for thereturn true
and a while loop to count seconds. The application continues to run on ctrl-c but closes after 5 seconds when closing with the X. -
glant over 6 yearsAbove solution does not work for me vb.net 4.5 framework ControlEventType is not getting resolved. I was able to use this idea as solution stackoverflow.com/questions/15317082/…
-
Steve Benz almost 6 yearsThere's a very subtle gotcha that this code avoids. You might look at this and think that the static _handler variable is not necessary, but it is. If you delete this, the handler may get garbage collected (because the unmanaged code doesn't hold a reference to it). If that happens, you'll get null reference exceptions when ctrl+C events are intercepted.
-
starbeamrainbowlabs over 5 yearsDoesn't catch CTRL + C for me with Mono on Linux.
-
John Zabroski almost 5 yearsInteresting that this seems to be the most robust answer. However, be careful about changing your console buffer size: if the buffer height is less than the window height, the program will throw an exception on startup.
-
Konard over 4 yearsIf you handle CTRL+C separately using
Console.CancelKeyPress
thenProcessExit
event actually raised after allCancelKeyPress
event handlers execution. -
Giacomo Pirinoli about 4 yearsI am sorry but using this code I am able to get "Cleanup complete" only if I press Ctrl+C, not if I close with 'X' button; in the latter case I get only "Exiting system due to external CTRL-C, or process kill, or shutdown" but then it seems the console closes before executing the remaining part of
Handler
method {using Win10, .NET Framework 4.6.1} -
Giacomo Pirinoli about 4 yearsI am sorry but this code seems to work when pressing Ctrl+C, not when clicking 'X' button; in the latter case if I put a sleep in the first line of
Handler
method I am not able to get it completed because the console closes before, even with debugger attached and breakpoint set after 1 or 2 seconds the console closes {using Win10, .NET Framework 4.6.1} -
JJ_Coder4Hire over 3 yearson windows 10 works for me CTRL-C, X on the window AND end process in Task Manager.
-
Robin Hartmann over 3 years@Konard I couldn't get
ProcessExit
to work, even if I registered a handler forCancelKeyPress
. Could it be that your handler forCancelKeyPress
does the same as yourProcessExit
handler, so it only seemed likeProcessExit
got called? -
Robin Hartmann over 3 years@JJ_Coder4Hire does it work for you if you select the root/parent console process in Task Manager and click
End Process
? For me it only works if I select the child console process (see my question for more information). -
Konard over 3 years@RobinHartmann I have retested that, and I got the same result - repl.it/@Konard/CultivatedForsakenQueryoptimizer These are two separate events and
ProcessExit
event is triggered afterCancelKeyPress
events. -
Robin Hartmann over 3 years@Konard Thanks for getting back to me, I also retested and this time I got
ProcessExit
to work, even withoutCancelKeyPress
. What I mean by that isProcessExit
gets called when the console is closed using the close button, even ifCancelKeyPress
isn't registered. But you needCancelKeyPress
, if you want to handleCTRL+C
andCTRL+Break
, becauseProcessExit
doesn't get called for those. -
Dan Randolph about 3 yearsThank you. it works great for me on Windows 10.