killing a process from task manager does not fire console CTRL_CLOSE_EVENT

S

shiry

Hi,
I need to do some important cleanup before my console application
exists. I used the console ctrl event. This is working well and it
fires for all cases, including the CTRL_CLOSE_EVENT (if I close the
application from the X botton). But on
the contrary to what the MSDN indicates
(ms-help://MS.VSCC.2003/MS.MSDNQTR.2003OCT.1033/dllproc/base/handlerroutine.htm),
ending my process from the task manager did not fire the
CTRL_CLOSE_EVENT.
I also tried to use the Appdomain processexit, which didn't work for
any of the cases.
This is the code as I tried it:
public enum ConsoleEvent
{
CTRL_C = 0,
CTRL_BREAK,
CTRL_CLOSE,
CTRL_LOGOFF = 5,
CTRL_SHUTDOWN
}
public delegate void ControlEventHandler(ConsoleEvent
consoleEvent);
public event ControlEventHandler ControlEvent;
ControlEventHandler eventHandler;
public ConsoleCtrlEventsSetup()
{
// save this to a private var so the GC doesn't
collect it...
eventHandler = new
ControlEventHandler(Handler);
SetConsoleCtrlHandler(eventHandler, true);
}
~ConsoleCtrlEventsSetup()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
void Dispose(bool disposing)
{
if (disposing)
{
GC.SuppressFinalize(this);
}
if (eventHandler != null)
{
SetConsoleCtrlHandler(eventHandler,
false);
eventHandler = null;
}
}
private void Handler(ConsoleEvent consoleEvent)
{
if (ControlEvent != null)
ControlEvent(consoleEvent);
}
[DllImport("kernel32.dll")]
static extern bool
SetConsoleCtrlHandler(ControlEventHandler e, bool
add);
}
class CrashHandler
{
public static void
MyProcessExitHandler(ConsoleCtrlEventsSetup.ConsoleEvent consoleEvent)
{
StopAllMotions();
}
public static void StopAllMotions ()
{
StreamWriter y =
File.AppendText(@"c:\temp\test.txt");
y.WriteLine("stopping all motions");
y.Flush();
y.Close();
}
}
public static void Main()
{
ConsoleCtrlEventsSetup cc = new
ConsoleCtrlEventsSetup();
cc.ControlEvent += new
ConsoleCtrlEventsSetup.ControlEventHandler(MyProcessExitHandler);
Console.WriteLine("Press any key to exit");
}
Any ideas?
Thanks.
 
S

Stoitcho Goutsev \(100\) [C# MVP]

shiry,

Task Manager provides two ways of ending a process - from the *Applications*
tab clicking on the *End Task* button and from the *Processes* tab clicking
on the *End Process* button.

The *End Task* button is the one that MSDN referes to. The ctrl event should
fire in this case.

I doubt it that you'll get the event if one clicks on the *End Process*
button, though. It even warns you when you do that.
Ending a process with this button is abnormal termination.
 
S

shiry

Thanks,
So, that means that I cannot catch an Application crash in this manner?
What about AppDomain.CurrentDomain.ProcessExit function, can it help me
in case of a crash?
I read somewhere that the only way to catch a crash, in order to do
some cleanup, is to run a watcher application that uses the
System.Diagnostics.Process class, and get the return code of the
application. Is that correct? Is there any other way of doing this?
 
W

Willy Denoyette [MVP]

shiry said:
Thanks,
So, that means that I cannot catch an Application crash in this manner?
What about AppDomain.CurrentDomain.ProcessExit function, can it help me
in case of a crash?
I read somewhere that the only way to catch a crash, in order to do
some cleanup, is to run a watcher application that uses the
System.Diagnostics.Process class, and get the return code of the
application. Is that correct? Is there any other way of doing this?

Killing a process is not an application crash isn't it?
When killing a process (from process explorer or whatever), the OS removes
the process cold, nothing is signaled because you are not supposed to kill a
process, unless it is no longer "functional", that is, it's no longer
runnable/responding, and because of this the OS sees no reason to signal the
process that it's going to be killed.
If you need to handle application crashes, you'll have to install a catch
handler.
Willy.
 
S

shiry

What do you mean by: "install a catch handler"?
(I'm pretty new to all this programming business, so excuse me for my
novice questions)
 
J

Justin Creasy

If you just need to do some cleanup, you can tie into the Process
Exited event. To do this you would have to have a watcher function like
you mentioned. All you would have to do is find your applications
Process object and use the following code.

Process currentProc = <your process, many ways to get this>;
currentProc.Exited += new EventHandler(processExited);

void processExited(object sender, EventArgs e)
{
//your clean up code goes here
}

Hope this helps
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Just make sure you set process.EnableRaisingEvents to *true* otherwise the
exit event won't fire.
 
J

Justin Creasy

Good call Stoitcho, I can't believe I forgot to mention that seeing as
I spent probably around 2 hours trying to find out why my event wasn't
firing and that was the answer. Thanks for catching that!
 
W

Willy Denoyette [MVP]

Justin Creasy said:
If you just need to do some cleanup, you can tie into the Process
Exited event. To do this you would have to have a watcher function like
you mentioned. All you would have to do is find your applications
Process object and use the following code.

Process currentProc = <your process, many ways to get this>;
currentProc.Exited += new EventHandler(processExited);

void processExited(object sender, EventArgs e)
{
//your clean up code goes here
}

Hope this helps

This doesn't work for our own process (CurrentProcess), it only works for
process spawned from this process.
So there is nothing you can do in your handler other than accessing some of
the process properties like ExitCode, ExitTime ....
The reason for this is that the event is raised by the OS to the parent of
the process after the process has terminated.

Willy.
 
W

Willy Denoyette [MVP]

shiry said:
What do you mean by: "install a catch handler"?
(I'm pretty new to all this programming business, so excuse me for my
novice questions)

Something like this for a console program, will catch unhandled
exceptions...

public static void DoSomethingNasty()
{
int x=0,y=1;
Console.Write((y/x).ToString()); // this will throw a "devide by zero"
exception
}
static void Main(string[] args)
{

AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(GenericErrorHandler);
// Start a thread and do something bad...
Thread t = new Thread(new ThreadStart(DoSomethingNasty));
t.Start();
t.Join();
}
static void GenericErrorHandler(object sender,UnhandledExceptionEventArgs
e)
{
Console.WriteLine("Exiting...");
System.Environment.Exit(1); // terminate process and return error code
1 to parent process
}


Note that this doesn't catch process terminated by a "Kill" command!!!

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top