Seems to have no effect when
a tcl shell is killed by another
process.
Trial code:
package require Tclx
set f [open test w]
signal trap SIGTERM "puts $f %S; exit"
....
then went to task manager and killed the process.
test file ends up empty so apparently the
puts didn't happen. Also tried SIGABRT
and SIGILL (no 'K') no difference. I don't
know if SIGILL is supposed to be a pun
but it is in the source code and SIGKILL
is actually rejected by the signal command
on my box.
Really anyway of trapping exit in plain tclsh
(not Tk) and doing a
necessary file i/o before the close would
be sufficient. TWAPI and winutls don't
seem to cover this case either. :-(
Also would just be nice to know
how much of signal actually works
on XP.
Thanks,
Roy
IIRC there is only a limited range of signals available on Windows.
Some are just in the header files but are never delivered by the
system.
Check
http://msdn2.microsoft.com/en-us/library/xdkz3x12.aspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_CRT_signal.asp
<quote>
sig value Description
SIGABRT Abnormal termination
SIGFPE Floating-point error
SIGILL Illegal instruction
SIGINT CTRL+C signal
SIGSEGV Illegal storage access
SIGTERM Termination request
--<snip-snip>--
The SIGILL, SIGSEGV, and SIGTERM signals are not generated under
Windows NT. They are included for ANSI compatibility. Thus you can
set signal handlers for these signals with signal, and you can
also explicitly generate these signals by calling raise.
</quote>
R'
rename exit _exit
proc exit {{code 0}} {
set fp [open test a]
puts $fp "trapped exit at [clock format [clock seconds]]"
_exit $code
}
But I don't think that will solve the OPs problem, when a process is
terminated by some other process (eg the taskmanager):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/terminating_a_process.asp
If a process is terminated by TerminateProcess, all threads of the
process are terminated immediately with no chance to run
additional code. This means that the thread does not execute code
in termination handler blocks. In addition, no attached DLLs are
notified that the process is detaching.
I would *guess* that this function is called by the taskmanager when
terminating a process. This would be the equivalent of kill -KILL [pid]
on Unix.
However, Ctrl-C on the windows *commandline* might be handled by
setting a console control handler:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/console_control_handlers.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/setconsolectrlhandler.asp
HTH
R'
Yes that's right
>
>
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/terminating_a_process.asp
> If a process is terminated by TerminateProcess, all threads of the
> process are terminated immediately with no chance to run
> additional code. This means that the thread does not execute code
> in termination handler blocks. In addition, no attached DLLs are
> notified that the process is detaching.
My main concern is cleanup when the whole system is
being rebooted. I suppose there are windows messages for that
case. Wonder if plain old tclsh can notice those messages or run
a child that would?
Thanks for helpful links to windows stuff.
Roy
Plain ol' tclsh does catch a reboot. Only if you're in the event loop,
I think, can it eval 'exit $code'
See win/tclAppInit.c in Tcl_AppInit() where it calls
SetConsoleCtrlHandler. The notification comes into sigHandler() from an
OS supplied thread. Just overload [exit] to grab it.
Roy,
I just looked, and nope.. it won't work.. win/tclAppInit.c:asyncExit()
is calling Tcl_Exit(). Tcl_Exit() bypasses the eval layer.
I'll try to fix it. Trouble is I can't just call Tcl_Eval() there as
it's a Tcl_AsyncProc and the Tcl_Interp stack could easily be in an
unsafe place. I'll have to add a call to Tcl_QueueEvent() there to come
around to a Tcl_EventProc, which is a safe place for a Tcl_Eval.
Soo.. ahh what exit codes make sense for these signals? I'm not sure
what to use. For a Ctrl+C [CTRL_C_EVENT], an unhandled app will exit
with a code of -1073741510 (signed) or 0xC000013A. That seems like the
valid choice as it'll be transparent.
What do you think I should do for values with the other 4 ?:
CTRL_BREAK_EVENT
CTRL_CLOSE_EVENT <- User pressed 'X' in upper right corner
CTRL_LOGOFF_EVENT
CTRL_SHUTDOWN_EVENT
Here's your patch if you're itching for a fix right now. I'm not sure
what values to use for exit codes. You can test it with a script like this:
rename exit _exit
proc exit {{code 0}} {
puts "requested to exit with $code"
_exit $code
}
vwait forever
C:\Programming\tcl_workspace\tcl_head_stock\win>release\tclsh85s
% source ../../../test.tcl
requested to exit with -1073741510 <- I pressed Ctrl+C
^C
C:\Programming\tcl_workspace\tcl_head_stock\win>echo %errorlevel%
-1073741510
C:\Programming\tcl_workspace\tcl_head_stock\win>release\tclsh85s
% source ../../../test.tcl
requested to exit with -1073741508 <- I pressed Ctrl+Break
C:\Programming\tcl_workspace\tcl_head_stock\win>
Cool! I will roll this into my next build.
And I'm wondering if the catch still work if the process is run
in the background. I'm working with Tcl-based
servers that are started by a windows service
with exec .... &
Happy New Year,
Roy
>
----------------------------------------------------------------------------
----
> *** win/tclAppInit.c 24 Jul 2005 22:56:45 -0000 1.22
> --- win/tclAppInit.c 27 Dec 2005 09:20:23 -0000
> ***************
> *** 31,39 ****
> static BOOL WINAPI sigHandler(DWORD fdwCtrlType);
> static Tcl_AsyncProc asyncExit;
> static void AppInitExitHandler(ClientData clientData);
>
> static Tcl_AsyncHandler exitToken = NULL;
> ! static DWORD exitErrorCode = 0;
>
>
> /*
> --- 31,47 ----
> static BOOL WINAPI sigHandler(DWORD fdwCtrlType);
> static Tcl_AsyncProc asyncExit;
> static void AppInitExitHandler(ClientData clientData);
> + static Tcl_EventProc eventExit;
>
> static Tcl_AsyncHandler exitToken = NULL;
> ! static DWORD signalCode = 0;
> !
> ! typedef struct {
> ! Tcl_Event header;
> ! DWORD exitCode;
> ! } signalExitEvent;
> !
> ! static Tcl_Interp *exitInterp;
>
>
> /*
> ***************
> *** 140,154 ****
> * Install a signal handler to the win32 console tclsh is running
in.
> */
>
> ! SetConsoleCtrlHandler(sigHandler, TRUE);
> ! exitToken = Tcl_AsyncCreate(asyncExit, NULL);
> !
> ! /*
> ! * This exit handler will be used to free the resources allocated in
this
> ! * file.
> ! */
>
> ! Tcl_CreateExitHandler(AppInitExitHandler, NULL);
>
> #ifdef TCL_TEST
> if (Tcltest_Init(interp) == TCL_ERROR) {
> --- 148,163 ----
> * Install a signal handler to the win32 console tclsh is running
in.
> */
>
> ! if (SetConsoleCtrlHandler(sigHandler, TRUE)) {
> ! /*
> ! * If successfully installed, create an async token for the
> ! * handler procedure and a clean-up routine for the token.
> ! */
>
> ! exitToken = Tcl_AsyncCreate(asyncExit, NULL);
> ! Tcl_CreateExitHandler(AppInitExitHandler, NULL);
> ! exitInterp = interp;
> ! }
>
> #ifdef TCL_TEST
> if (Tcltest_Init(interp) == TCL_ERROR) {
> ***************
> *** 369,378 ****
> * The AsyncProc for the exitToken.
> *
> * Results:
> ! * doesn't actually return.
> *
> * Side effects:
> ! * tclsh cleanly exits.
> *
> *----------------------------------------------------------------------
> */
> --- 378,387 ----
> * The AsyncProc for the exitToken.
> *
> * Results:
> ! * result of last command.
> *
> * Side effects:
> ! * an event is queued.
> *
> *----------------------------------------------------------------------
> */
> ***************
> *** 383,397 ****
> Tcl_Interp *interp, /* interp in context, if any. */
> int code) /* result of last command, if any. */
> {
> ! Tcl_Exit((int)exitErrorCode);
>
> - /* NOTREACHED */
> return code;
> }
>
> /*
> *----------------------------------------------------------------------
> *
> * sigHandler --
> *
> * Signal handler for the Win32 OS. Catches Ctrl+C, Ctrl+Break and other
> --- 392,453 ----
> Tcl_Interp *interp, /* interp in context, if any. */
> int code) /* result of last command, if any. */
> {
> ! signalExitEvent *ev;
> !
> ! ev = (signalExitEvent *) Tcl_Alloc(sizeof(signalExitEvent));
> ! ev->header.proc = eventExit;
> !
> ! switch (signalCode) {
> ! case CTRL_C_EVENT:
> ! ev->exitCode = CONTROL_C_EXIT; break;
> ! case CTRL_CLOSE_EVENT:
> ! ev->exitCode = CONTROL_C_EXIT+1; break;
> ! case CTRL_BREAK_EVENT:
> ! ev->exitCode = CONTROL_C_EXIT+2; break;
> ! case CTRL_LOGOFF_EVENT:
> ! ev->exitCode = CONTROL_C_EXIT+3; break;
> ! case CTRL_SHUTDOWN_EVENT:
> ! ev->exitCode = CONTROL_C_EXIT+4; break;
> ! }
> ! Tcl_QueueEvent((Tcl_Event *)ev, TCL_QUEUE_TAIL);
>
> return code;
> }
>
> /*
> *----------------------------------------------------------------------
> *
> + * eventExit --
> + *
> + * The Tcl_EventProc for evaluating [exit $code] due to an OS
> + * signal.
> + *
> + * Results:
> + * Doesn't return.
> + *
> + * Side effects:
> + * tclsh cleanly exits.
> + *
> + *----------------------------------------------------------------------
> + */
> +
> + int
> + eventExit(
> + Tcl_Event *evPtr,
> + int flags)
> + {
> + Tcl_Obj *words[2];
> +
> + words[0] = Tcl_NewStringObj("exit", -1);
> + words[1] = Tcl_NewLongObj(((signalExitEvent *)evPtr)->exitCode);
> + Tcl_EvalObjv(exitInterp, 2, words, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
> + /* NOTREACHED */
> + return 1;
> + }
> +
> + /*
> + *----------------------------------------------------------------------
> + *
> * sigHandler --
> *
> * Signal handler for the Win32 OS. Catches Ctrl+C, Ctrl+Break and other
> ***************
> *** 427,433 ****
> * will cause Tcl to enter asyncExit at the next command boundry.
> */
>
> ! exitErrorCode = fdwCtrlType;
> Tcl_AsyncMark(exitToken);
>
> /*
> --- 483,489 ----
> * will cause Tcl to enter asyncExit at the next command boundry.
> */
>
> ! signalCode = fdwCtrlType;
> Tcl_AsyncMark(exitToken);
>
> /*
>
>
>Cool! I will roll this into my next build.
>And I'm wondering if the catch still work if the process is run
>in the background. I'm working with Tcl-based
>servers that are started by a windows service
>with exec .... &
>
>Happy New Year,
>Roy
Yes, they will. But there's an issue when run as a service. You're
going to have to "catch" the logoff event and ignore it. Something
like this:
rename exit _exit
proc exit {{code 0}} {
switch {$code} {
case 0xC0000013D {
# temporary exit code for CTRL_LOGOFF_EVENT
puts "doh! we ain't shutting down for a logoff event!"
return -code continue
}
default {
_exit $code
}
}
}
You might consider a real service shell instead, like Matt Newman's
(?) tclservice. tclsh is a shell for being a console application ;)
With a service shell, you have builtin commands for start, stop,
install, and uninstall and understands how to behave properly under
the service manager.
I'll test the script out. The patch might require a change.
proc exit {{code 0}} {
switch -- $code {
-1073741507 {
# temporary exit code for CTRL_LOGOFF_EVENT
puts "doh! we ain't shutting down for a logoff event!"
return -code continue
}
default {
puts "requested to exit with $code"
_exit $code
}
}
}
with a small change to the patch for this function:
int
eventExit(
Tcl_Event *evPtr,
int flags)
{
Tcl_Obj *words[2];
int result;
words[0] = Tcl_NewStringObj("exit", -1);
words[1] = Tcl_NewLongObj(((signalExitEvent *)evPtr)->exitCode);
result = Tcl_EvalObjv(exitInterp, 2, words,
TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
if (result == TCL_ERROR) {
Tcl_BackgroundError(exitInterp);
}
Tcl_ResetResult(exitInterp);
return 1;
}
We need real values for the exit codes.
case CTRL_LOGOFF_EVENT:
ev->exitCode = CONTROL_C_EXIT+3; break;
That doesn't make much sense to me. CONTROL_C_EXIT+3 ???
>To clarify: I do have a proper win. service executable built with
>ActiveState
>TclDevkit. That service, in turn, starts various tclsh.exe to do the "real
>work"
>with stdout and stderr redirected to regular files.
>Are you saying these spawned tlcsh processes are somehow
>not kosher uses of the tcl shell?
Ok, no problem then as these are children. I wouldn't recommend using
tclsh as the front-end with that service tool that came with the NT
resource kit. A company I used to work did that, and was never able
to get shutdown notices properly for their TclPro (old, 1.4) wrapped
tclhttpd
Hmm.. <thinking/>
But with this patch, I guess you could use tclsh even as a front-end
and trap/ignore logoffs anyways.
The big issue years ago was that tclsh wasn't getting signaled for a
clean exit when the system was shutdown,logoff,ctrl+c,ctrl+break,or
console window closure. "Hey, my [Incr Tcl] destructors aren't
getting called! WTF?"
Ok, that got fixed about 2001 so all app closures cause Tcl_Finalize()
to run. Then I got email about it closing by itself when tclsh was
run as a service through the NT resource service helper. So we (me
and Jeff) told people to use a real service shell instead as tclsh is
specifically a console application. There's a correct service shell
available.
So now we have you requesting a way to trap these OS specific signals,
and I agree fully for the need to fire special cleanup routines. But
wait a sec.. you can't trap them at the script level... whoa.. Got
a prelim patch done. It seems to work. I have no idea what the
correct exit codes should be for logoff,shutdown,and IFclose.
ctrl+break isn't/shouldn't be ignorable. ctrl+c can be. That's about
where it sits for the moment.
Is this tclsh abuse running it as a child of a service? Not at all.
Just this special ignore for logoff is needed.
I was thinking about this some more and I don't think this signal
stuff should be in tclsh at all.
It should be in an extension or something.
Here's why I think this.. To properly "trap" a signal I need to
assume the event loop is running. I think that's a bad asumption to
make for everyone by placing this code in the shell itself.
but where is the difference to things like fileevent?
uwe
>> Here's why I think this.. To properly "trap" a signal I need to
>> assume the event loop is running. I think that's a bad asumption to
>> make for everyone by placing this code in the shell itself.
>
>but where is the difference to things like fileevent?
By taking the responsibility to install a handler, I should be certain
that when I call Tcl_AsyncMark, the queued event will get serviced. If
it doesn't get serviced, the blocking with Tcl_ConditionWait for the
return value to exit the handler will block the OS supplied thread for
infinity.
I could do a timeout I guess... Ok, this is probably workable but
tclsh would require a threaded build or... I'll just use a native
event object..
Why are you thinking in terms of something so elaborate? The async stuff
(Tcl_AsyncCreate/Tcl_AsyncMark) is designed specifically for handling
interrupts, and the interpreter always services the async stuff (using
Tcl_AsyncReady) when it is in a reentrant state. Fiddling around with
lots of thread stuff is just a way to get confused. (The async API is
how the TclX and Expect extensions handle signals on UNIX.)
Of course, the async handler you set up with Tcl_AsyncCreate could just
post an event to the event queue. That'd work just fine. But that's a
higher-level operation, and could be written in Tcl because you've got a
reentrant interpreter by the time it runs...
Donal.
TclX and Expect don't do it right. It isn't safe to eval scripts
within the context of a Tcl_AsyncProc. Try it.. use a dual CPU
machine, some deep Itcl scopes and hammer Tcl_AsyncMark and watch Tcl
crash in random spots. From the Tcl_AsyncProc, Tcl_QueueEvent, then
eval in the Tcl_EventProc and all is safe.
That and I have to use the script result to determine the proper
return value from the handlerroutine which means block until the
script runs.
/Ashok
You buy me that dual-processor machine and I'll do just that. :-D
More seriously, if it doesn't work there's a bug since the async proc
should only ever be executed in a context where it is safe to run
scripts. That's its whole purpose.
Also, if you can only duplicate the problem with Itcl, it's possible
that it is a fault in Itcl and not Tcl itself. Itcl does some odd things
internally.
> That and I have to use the script result to determine the proper
> return value from the handlerroutine which means block until the
> script runs.
Why? Just return immediately a result of "Got it, will take action
myself, you can stop bothering me now" and let the user-scripts decide
whether to exit or what. Blocking in what is essentially an interrupt
handler is something I've always been taught to regard as a bad idea.
Donal.
Well, I guess it's there after all. I wondered if
the "console" functions would work when the app is
run in background. I suppose this is a case where "console"
refers more to the application build type (as opposed to win32/gui)
than it refers to the manifest cosole widow on the display.
In any case, it seems to work but somewhat
confusingly to me.
CODE:
# test sighandling for shutdown
set f [open test w]
proc bootsig sig {
# we really want to ignore logoff
global f
puts $f "Got SIG $sig"
flush $f
return 0 ;# default action
}
package require twapi
twapi::set_console_control_handler bootsig
vwait forever
END CODE
On change of logins this code apparently does nothing.
On logout the process exists and the
file contains "got SIG logoff"
On system restart the
file also contains "got SIG logoff" (not "SIG shutdown")
If I modify the code to return non-zero for "logoff"
if {$sig eq "logoff"} {return 1}
then WidowsXP reports it can't close the program on
user-initiated reboot. "Windows cannot end this program.
It may need more time to complete an operation."
These test were with the sample code run from a console tclsh
via exec ... &
In production the starting program will be a windows service. Perhaps
that will make a difference.
In any case the goal would be to keep running and only
invoke special action when the system
is truely shutting down. Any number of logins and user changes
should have no effect at all. So I don't understand not
being able to catch the shutdown event.
Suggestions or explainations?
Thanks,
Roy
>
> /Ashok
>
>So I don't understand not
>being able to catch the shutdown event.
It's possible, but intested, that the default one in tclsh could be
interfering.
On system shutdown, Windows will first send the logoff event followed
by a shutdown event. When the logoff event is received, the handler is
invoked, writes to the file and returns 0. Windows then calls the next
registered handler (since your handler returned 0). If this is either
the tclsh handler or the default handler, the process will exit. It
therefore never sees the shutdown event being sent as it has already
exited. On the other hand, if you return 1 from the handler, Windows
will not call futher handlers but then it will display the popup that
the process is not exiting.
In any case, if your eventual goal is to run this as a service, using
console handlers is the wrong approach as they are not called for
service processes AFAIK. Instead you need to trigger on the service
stop signal. I don't know if any of the Tcl Windows service packages
allow for handling the service stop event at the Tcl script level.
/Ashok
palmtcl write:
> if you return 1 from the handler, Windows will not call futher
> handlers but then it will display the popup that the process is not
> exiting.
There is a trick to get a longer timeout before that popup (your
description triggered a dim memory and I dug up the code ;-) ):
DWORD prio, retry;
GetProcessShutdownParameters( &prio, &retry );
retry &= ~((DWORD)SHUTDOWN_NORETRY);
SetProcessShutdownParameters( prio, retry );
> In any case, if your eventual goal is to run this as a service,
> using console handlers is the wrong approach as they are not called
> for service processes AFAIK.
Actually they are, at least sometimes, and I do not remember the exact
circumstances. Only that it always happened at the most inconvenient
times for us.
> Instead you need to trigger on the service stop signal.
But you are right of course, that this is the main standard service
interface.
benny
> palmtcl write:
>> if you return 1 from the handler, Windows will not call futher
>> handlers but then it will display the popup that the process is not
>> exiting.
>
Benjamin Riefenstahl writes:
> There is a trick to get a longer timeout before that popup (your
> description triggered a dim memory and I dug up the code ;-) ):
>
> DWORD prio, retry;
> GetProcessShutdownParameters( &prio, &retry );
> retry &= ~((DWORD)SHUTDOWN_NORETRY);
> SetProcessShutdownParameters( prio, retry );
Looks like I misunderstood my own notes on this, sorry. What this
code does is *enable* the popup dialog, if it was disabled before.
When the popup is enabled, the system timeout is longer, and you have
more time to cleanup and exit, even while the dialog is already up.
When the popup is disabled, your process is just terminated after the
system timeout, so your cleanup may be cut short at that point. I
think the popup is disabled for services, so that was why we wanted
this code.
benny
>David Gravereaux wrote:
>> TclX and Expect don't do it right. It isn't safe to eval scripts
>> within the context of a Tcl_AsyncProc. Try it.. use a dual CPU
>> machine, some deep Itcl scopes and hammer Tcl_AsyncMark and watch Tcl
>> crash in random spots. From the Tcl_AsyncProc, Tcl_QueueEvent, then
>> eval in the Tcl_EventProc and all is safe.
>
>You buy me that dual-processor machine and I'll do just that. :-D
>
>More seriously, if it doesn't work there's a bug since the async proc
>should only ever be executed in a context where it is safe to run
>scripts. That's its whole purpose.
Well, it isn't. It never was. The yielding of TclExecuteByteCode()
is in between bytecoded blocks. And in that place, the state of the
interp is unknown. What scope are we? What vars are local? Are we
in a namespace?
Even in the man page its full of warnings. The best place to eval a
script with a clear interp is from a Tcl_EventProc.
>Also, if you can only duplicate the problem with Itcl, it's possible
>that it is a fault in Itcl and not Tcl itself. Itcl does some odd things
>internally.
Naww, it's all about the grain of where the execution state is
yeilded. Ok, the old Tcl_Finalize called from another thread than the
event loop bug is gone as well as the old Tcl_AsyncProcs running in
other threads than the one it was created in.
Ok, you won't have crashes.. sorry was in the 8.1 headset days when I
was experimenting heavy with Tcl_AsyncMark.
You will be in strange/undefined interp states, though.
Tcl_AsyncProcs are only safe for _memory allocation routines_ which
doesn't union with any API that uses a Tcl_Interp pointer.
>> That and I have to use the script result to determine the proper
>> return value from the handlerroutine which means block until the
>> script runs.
>
>Why? Just return immediately a result of "Got it, will take action
>myself, you can stop bothering me now" and let the user-scripts decide
>whether to exit or what.
If the script can even get that far before the OS terminates it.
Ctrl+Break can't be trapped. That's why I need to block it. But I'll
do it with a timeout for safety.
> Blocking in what is essentially an interrupt
>handler is something I've always been taught to regard as a bad idea.
Better than exit handler scripts not running cause the OS killed it
before the event loop came around? Once you let the "HandlerRoutine"
return, the app needs to be done with the work it needs to do for that
signal.
>If this is either
>the tclsh handler or the default handler, the process will exit.
Yup, the tclsh one is interfeering..
Ok, should it go away? place your votes here.. I'm swaying to a
strong yes. Let's let extensions add the good details we need.
>In any case, if your eventual goal is to run this as a service, using
>console handlers is the wrong approach as they are not called for
>service processes AFAIK.
Yes, they are called, but the default handler's behavior is different.
Logoff is ignored properly. And there's something about the "end now"
dialog behavior/timeouts being different, too.
>In any case, if your eventual goal is to run this as a service, using
>console handlers is the wrong approach as they are not called for
>service processes AFAIK. Instead you need to trigger on the service
>stop signal.
Roy is doing that. But this is for children of the main app that are
using plain tclsh.
Well duh! The handler only ever makes sense when executing at the global
level. I thought I didn't need to say that. :-)
> Even in the man page its full of warnings. The best place to eval a
> script with a clear interp is from a Tcl_EventProc.
Usually, the best thing to do from the callback will be to post an
event, yes. But not always (e.g. if there's no event queue used in the
program) so it is best left as something scripted.
> Tcl_AsyncProcs are only safe for _memory allocation routines_ which
> doesn't union with any API that uses a Tcl_Interp pointer.
As I said, executing the script in the current context is not a good
thing to do anyway. Indeed, it's pretty mind-boggling that anyone would
choose to do so. :-)
> If the script can even get that far before the OS terminates it.
> Ctrl+Break can't be trapped. That's why I need to block it. But I'll
> do it with a timeout for safety.
I don't yet understand, but then I'm a unix guy when it comes to
programming. On that platform, most signals (including those sent in
response to normal user activity) are trappable but have a default
handler set that causes the process to exit. How does Ctrl+Break differ
from this model?
> Better than exit handler scripts not running cause the OS killed it
> before the event loop came around? Once you let the "HandlerRoutine"
> return, the app needs to be done with the work it needs to do for that
> signal.
Yuck. That's really quite different indeed. (Thanks for the name
"HandlerRoutine"; that lets me find helpful information in MSDN that
answers most of my questions.)
And yet, it must be possible to veto the auto-exiting of a process in
response to CTRL_C_EVENT and CTRL_BREAK_EVENT. After all, the Windows
ping command does just that when the -t flag is passed. I wonder if
terminating the thread executing the handler would do the trick? But
then what ping does seems to be different to what SetConsoleCtrlHandler
implies is possible...?
Now I'm more confused than I was!
Donal.