Geeks With Blogs
Nat Luengnaruemitchai Geek Blog

There are mainly 2 types of Win32 applications, console application and window application. They have different way in handling application exit. To force Window application to exit, you need to send out WM_CLOSE message to the main window handle. That's pretty simple to handle. You can hook up to Application.ApplicationExit or Form.Close at the form level. However, in a console application, it is a little bit different. Console applications are somehow modeled after DOS console application where usually an application exits when stdin is dead or Ctrl+C is pressed. To handle this properly in C#, you can set a delegate to SetConsoleCtrlHandler.You will have an opportunity to clean up resource or finish your work before the application actually exits. 

// Declare the SetConsoleCtrlHandler function
// as external and receiving a delegate.

[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;
}

...

SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

// Most of the code was from MSDN

Posted on Thursday, September 23, 2004 7:39 AM | Back to top


Comments on this post: Detecting Process Exit From Console Application in C#

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
A console application is essentially a windows application but with a message loop. All processes on Windows are Win32 processes. U forgot about Win32 services in your Win32 application list above.

I suspect the above handler will not be called when it gets an ExitProcess
Left by Matt on Oct 01, 2004 5:34 AM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
True that a console application is just a win32 app but with the fact that it doesn't have a message loop. Therefore, it cannot receive WM_CLOSE. Seem that hooking into SetConsoleCtrlHandler is one of a few ways to monitor such event. Read more from http://www.codeproject.com/win32/console_event_handling.asp?print=true

Nat
Left by Nat on Oct 02, 2004 2:50 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
Is any of these signal emited when I kill a process using the .Net Process.Kill method.
I have an console application that need to do some clean up before it terminates.
Could I use this or do I have to rewrite it as a windows application?
Left by Tony on Oct 15, 2004 4:23 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
Process.Kill will internally call native method called TerminateProcess which is a harsh way to terminate the process. The application in that process will not have a chance to clean up anyway at all. You might consider to use Process. You might try to use Process.CloseMainWindow instead. I haven't tried that with SetConsoleCtrlHandler yet though. Please let me know if you test it :)
Left by Nat on Oct 17, 2004 8:51 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
I tested it but didn't get any 'event' fired.
Here is how I understand the design:
The SetConsoleCtrlHandler works only if you start your program from a console (duh!), meaning from a 'cmd' window. In that case, when you close the console window, the cmd program (which is a window application) receives the WM_CLOSE message and translates it into the righ 'event'.
But if you start your program any other way (by using Start\Run... for instance), then the program will never receive any of these events because there is no Windows Application hosting yours.

I wish Microsoft had done a better job at designing the application object model. I find it amazing that you have different ways to do the same thing depending on whether you implement a Console application, a Windows Service or a Windows application.

Thanks for the blog entry anyway. It was very informative.


Left by Tony on Nov 17, 2004 10:15 AM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
I confirm that if you use Start/Run, it will work as well..... this thing will work with .NET application which is compiled as console application only. If you want to use it as a window application, you need to hook up to an event inside Application class.
Left by Nat on Nov 17, 2004 5:40 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
Its very simple, put below line in Constructor.

this.Closed +=new EventHandler(Form1_Closed);

And, the below function will be invoked while closing the application.

private void Form1_Closed(object sender, EventArgs e)
{
///Your Code
}
Left by Rajendran on Apr 08, 2005 1:25 AM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
I have a console app and when using MORE, I loose focus to the console window and have to click on the titlebar. When I close the window a second window appears and has to be close also. I don't see this when using TYPE myfile | MORE.

John
Left by John Spikowski on Jul 16, 2005 11:11 AM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
Use Console.CancelKeyPress, only works with CTRL+C key presses though
Left by Nick on Apr 19, 2006 4:26 AM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
This is helpful, but I have a question along the same lines, what if I want to programatically send the Ctrl+C myself to the console app?

Take this code:
GenerateConsoleCtrlEvent( XConsoleEvent.CTRL_C, 0);

The second argument (0) is the ProcessGroupID. If I set this to zero the console app received the Ctrl+C and exits, but so does the calling application.

You wouldn't happen to know anything about this would you?
Left by M. on May 02, 2006 11:57 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
M,
When you use the Process class there is no method currently exposed to set the ProcessGroupID and as such the ProcessGroupID is set the same as the calling app. There are ways around this like creating another app that send the CTRL-C:

static int Main(string[] args)
{
int processId = int.Parse(args[0]);
if (!FreeConsole())
return 1;
if (!AttachConsole(processId))
return 1;
if (!GenerateConsoleCtrlEvent(ConsoleCtrlEvent.CTRL_C, 0))
return 1;
return 0;
}
Left by J on May 20, 2006 8:44 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
So, does this work with a "Windows Service" the same way as the "Console" app?
Left by loterbol on Jul 24, 2006 11:03 AM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
I can only confirm what Nick said: Just handle Console.CancelKeyPress, it's a one-liner and works under any circumstances I've tested...
Left by Markus on Feb 20, 2007 7:02 AM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
Warning about this code: It's the correct means of handling the event, but there's a problem in the call to SetConsoleCtrlHandler(). If you don't hold onto a reference to the HandlerRoutine instance, it can be garbage collected. The reference held by SetConsoleCtrlHandler() is not counted.
Left by Andy Lippitt on Jan 08, 2008 2:11 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
Hi,
I've another problem. Under Debug everything is ok ...but when I want to make released version it crashed !?!? anyone know why ?

BR
Marceli
Left by ossi on Dec 11, 2008 6:52 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
I found it , as Andy has written : it's CallbackOnCollectedDelegate and GarbageCollector

how can I solved it ?
Left by ossi on Dec 11, 2008 9:28 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
You just need to instantiate a HandlerRoutine object.

HandlerRoutine hr = new HandlerRoutine(ConsoleCtrlCheck);
SetConsoleCtrlHandler(hr, true);
Left by Megumi on Jan 22, 2009 11:01 PM

# re: Detecting Process Exit From Console Application in C#
Requesting Gravatar...
Hello all.
I am using a code similar to the one listed at the top of the post. It worked OK for me (detecting closing events) but it didn't work anymore since I added code to create a new thread within the main method. That is:

static void Main() {

HandlerRoutine hr = new HandlerRoutine ConsoleCtrlCheck);
SetConsoleCtrlHandler(hr, true);

// thread creation
SubscriberCAllBack scb = new SubscriberCAllBack();
oThread = new Thread(new ThreadStart(scb.ListenToAlarms));
oThread.IsBackground = true;
oThread.Start();

// MainApp is a Windows Form class
Application.Run(new MainApp());

}

The thing is that, if I dont create the thread inside the main, it works. But it does not when spawning the thread.
Is there any kind of incompatibility between the reception of console closing events and the use of threads?

Thanks for your help.
angel_pr1984@hotmail.com
Left by Hebbo on Jan 28, 2009 12:09 AM

Your comment:
 (will show your gravatar)


Copyright © Nat Luengnaruemitchai | Powered by: GeeksWithBlogs.net | Join free