12

So my batch script is ticking along nicely when suddenly this appears in the output log:

21:27:13.99 c:\apps\w7lab-scripting>some-command
Error 3221225786
^CTerminate batch job (Y/N)? 

and the script stops dead.

The batch script is running in session zero, so I know it didn't receive a real control-C, and none of my code calls GenerateConsoleCtrlEvent so that can't be it. The only clue is that some-command was communicating with an interactive application at the time, and that application's console received a control-C. The expected behaviour was for some-command to display the other application's exit code, then exit with the same code. The batch script would have dealt with the error appropriately, if it hadn't stopped dead.

What's going on here?

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158

2 Answers2

19

The magic here is in exit code 3221225786, aka 0xC000013A or STATUS_CONTROL_C_EXIT.

The interactive application received a control-C, and didn't catch it, so as expected, it was aborted with STATUS_CONTROL_C_EXIT. The some-command application correctly reported this as the remote application's exit code, and passed it back to the batch script.

What I hadn't realized was that cmd.exe detects control-C in a batch script in exactly this way, by checking whether a child process returns STATUS_CONTROL_C_EXIT. So by returning this error code I was inadvertently stopping the batch script.

This can be demonstrated with a simple batch script:

cmd /c exit 3221225786
echo hello

which, when run, produces

C:\working\test>cmd /c exit 3221225786
^CTerminate batch job (Y/N)?
dbenham
  • 127,446
  • 28
  • 251
  • 390
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • Whoa, That is freaky! Nice find. It also works with an exit code of -1073741510. It also works with or without the /B option. FOR /F can capture the Ctrl-C character. – dbenham Aug 23 '14 at 05:49
  • Oops - I fooled myself. The `^C` that FOR /F can capture if stderr is redirected to stdout is not the Ctrl-C character. It is actually a two character string consisting of a caret followed by the letter C. – dbenham Aug 23 '14 at 21:24
  • @dbenham: yes, I believe `cmd.exe` is outputting "caret C" as a visual cue for the user. Presumably this is done by the same logic that handles an actual control-C rather than something extra, but I'm hazy on the details of how control-C handling works when there are multiple processes sharing the same console. – Harry Johnston Aug 24 '14 at 00:41
  • 4
    I have discovered a good use for this feature. It can be used to cleanly exit batch processing from within a CALLed routine. See http://stackoverflow.com/a/25474648/1012053 – dbenham Aug 24 '14 at 18:54
-2

Alternatively, it is possible to terminate batch session using commands that provoke brutal batch end (from https://superuser.com/a/805637), any of the following (attempting to feed STDERR to STDIN breaks):

cd invalidPath 2>&0
vol x 2>&0    
move nonExistentFile 2>&0
set nonExistentVariable 2>&0
dir nonExistentFile 2>&0

So, a subroutine could be:

:SubSelfTerminate
    cd invalidPath 2>&0
exit /b 0

which would be called from Main batch as:

call :SubSelfTerminate

Note: "exit /b 0" in subroutine is useless as will always be ignore it is used but mark the end the subroutine.

  • This doesn't appear to answer the question asked. Did you intend to post it as an answer to [this question](https://stackoverflow.com/q/3227796/886887)? – Harry Johnston Dec 09 '20 at 10:53
  • @HarryJohnston mods can't merge a single answer into another question. Merge questions = all answers moved. – Samuel Liew Dec 17 '20 at 01:02