programmatically "press" Ctrl-C / Exit batch inside CALL

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
dbenham
Expert
Posts: 2388
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

programmatically "press" Ctrl-C / Exit batch inside CALL

#1 Post by dbenham » 23 Aug 2014 15:22

I found this amazing/surprising feature at http://stackoverflow.com/q/25444765/1012053. Maybe someone can find a use for it.
Update - Scroll down to the 5th post to see how it can be used to cleanly exit from batch processing, regardless how many CALLs have been issued.

Here is a very simple TEST.BAT:

Code: Select all

@echo off
:loop
echo before
cmd /c exit -1073741510
echo after
echo(
goto loop

The Ctrl-C exit code returned from CMD /C is interpreted the same as if someone pressed the Ctrl-C key. The same effect is achieved with a return value of 3221225786.

Here is sample output with 2 iterations, first entering "n", then "y":

Code: Select all

C:\test>test
before
^CTerminate batch job (Y/N)? n
after

before
^CTerminate batch job (Y/N)? y

C:\test>


The ^C that displays can be hidden by redirecting stderr to nul. It is not the actual Ctrl-C character.

Code: Select all

@echo off
:loop
echo before
cmd /c exit -1073741510 2>nul
echo after
echo(
goto loop

sample output:

Code: Select all

C:\test>test
before
Terminate batch job (Y/N)? n
after

before
Terminate batch job (Y/N)? y

C:\test>


The ^C display is not the actual Ctrl-C character. It is actually a caret, followed by C, which is displayed on stderr when CMD.EXE detects Ctrl-C. That can be seen by redirecting stderr to stdout, and capturing the value with FOR /F.

Code: Select all

@echo off
setlocal enableDelayedExpansion
for /f %%C in ('cmd /c exit -1073741510 2^>^&1') do (
  set "str=%%C"
  echo str[0]=!str:~0,1!
  echo str[1]=!str:~1,1!
)

output:

Code: Select all

str[0]=^
str[1]=C


Dave Benham
Last edited by dbenham on 24 Aug 2014 09:44, edited 1 time in total.

aGerman
Expert
Posts: 3940
Joined: 22 Jan 2010 18:01
Location: Germany

Re: programmatically "press" Ctrl-C

#2 Post by aGerman » 24 Aug 2014 04:28

Hi Dave

Thath's quite interesting even if I believe it must be some kind of a bug. I can't believe it was intention to signal that message via return value :?
I tried a few other values found at the related MSDN site yet without success ...

Regards
aGerman

dbenham
Expert
Posts: 2388
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: programmatically "press" Ctrl-C

#3 Post by dbenham » 24 Aug 2014 06:08

aGerman wrote:That's quite interesting even if I believe it must be some kind of a bug. I can't believe it was intention to signal that message via return value :?
I'm not so sure... It is the error code that indicates Ctrl-C termination.

aGerman wrote:I tried a few other values found at the related MSDN site yet without success ...
I'm curious - just what kind of effect were you expecting for other return codes to indicate "success"?


Dave Benhaqm

aGerman
Expert
Posts: 3940
Joined: 22 Jan 2010 18:01
Location: Germany

Re: programmatically "press" Ctrl-C

#4 Post by aGerman » 24 Aug 2014 08:18

dbenham wrote:
aGerman wrote:That's quite interesting even if I believe it must be some kind of a bug. I can't believe it was intention to signal that message via return value :?
I'm not so sure... It is the error code that indicates Ctrl-C termination.

I'm also not sure, but the description says "The application terminated as a result of a CTRL+C". Since you never pressed CTRL+C it's at least a bit strange from my point of view.

dbenham wrote:I'm curious - just what kind of effect were you expecting for other return codes to indicate "success"?

I actually didn't expect that anything else could affect the batch window because I assume it's just undefined behavior.
I tried with values like STATUS_FATAL_APP_EXIT and STATUS_PROCESS_IS_TERMINATING. I thought it would let the process freeze or whatever ...

Regards
aGerman

dbenham
Expert
Posts: 2388
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: programmatically "press" Ctrl-C / Exit batch inside CALL

#5 Post by dbenham » 24 Aug 2014 09:39

This feature is actually quite useful :!:
:idea: It can be used to cleanly exit all batch processing, regardless how many CALLs have been issued.

In past threads, jeb has shown how a fatal syntax error can be used to exit batch processing while within a CALL (I failed to find a link). But that technique can corrupt the environment because the implicit ENDLOCAL mechanism does not work properly: See viewtopic.php?p=9199#p9199

Here is a TEST.BAT that demonstrates how the programmatic Ctrl-C "press" can be used to cleanly exit from batch processing while within a CALL.

Code: Select all

@echo off
setlocal
set test=AFTER 1st SETLOCAL
setlocal
set test=AFTER 2nd SETLOCAL
call :sub1
echo returning from main  NEVER REACHED
exit /b

:sub1
setlocal
set test=AFTER sub1 1st SETLOCAL
setlocal
set test=AFTER sub1 2nd SETLOCAL
call :sub2
echo returning from sub1 NEVER REACHED
exit /b

:sub2
setlocal
set test=AFTER sub2 1st SETLOCAL
setlocal
set test=AFTER sub2 2nd SETLOCAL
set test
call :ExitBatch
echo returning from sub2 NEVER REACHED
exit /b


:ExitBatch - Cleanly exit batch processing, regardless how many CALLs
if not exist "%temp%\ExitBatchYes.txt" call :buildYes
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1
:CtrlC
cmd /c exit -1073741510

:buildYes - Establish a Yes file for the language used by the OS
pushd "%temp%"
set "yes="
copy nul ExitBatchYes.txt >nul
for /f "delims=(/ tokens=2" %%Y in (
  '"copy /-y nul ExitBatchYes.txt <nul"'
) do if not defined yes set "yes=%%Y"
echo %yes%>ExitBatchYes.txt
popd
exit /b

sample run output:

Code: Select all

C:\test>test
test=AFTER sub2 2nd SETLOCAL

C:\test>set test
Environment variable test not defined
The entire CALL stack of SETLOCAL has been properly handled, so variable test is no longer defined upon batch termination. If a fatal syntax error were used instead of the :ExitBatch routine, then test would still be defined as AFTER sub2 2nd SETLOCAL upon batch termination.

The routine can be put into a stand-alone script named ExitBatch.bat and placed somewhere within the PATH. Then it can be conveniently used as needed by any batch script.

Code: Select all

@echo off
:ExitBatch - Cleanly exit batch processing, regardless how many CALLs
if not exist "%temp%\ExitBatchYes.txt" call :buildYes
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1
:CtrlC
cmd /c exit -1073741510

:buildYes - Establish a Yes file for the language used by the OS
pushd "%temp%"
set "yes="
copy nul ExitBatchYes.txt >nul
for /f "delims=(/ tokens=2" %%Y in (
  '"copy /-y nul ExitBatchYes.txt <nul"'
) do if not defined yes set "yes=%%Y"
echo %yes%>ExitBatchYes.txt
popd
exit /b


Dave Benham

einstein1969
Expert
Posts: 776
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: programmatically "press" Ctrl-C / Exit batch inside CALL

#6 Post by einstein1969 » 24 Aug 2014 12:41

@Dave
I don't know if the jeb method is the same for exit from a infinite for loop...

here jeb use the HALT method . Here suggest to use.

this is the method you mentioned?

jeb
Expert
Posts: 967
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: programmatically "press" Ctrl-C / Exit batch inside CALL

#7 Post by jeb » 25 Aug 2014 05:32

@Dave

Very nice technic :D

I tried a bit to use CTRL-C for another cmd.exe thread, but currently all my attempts fail.

I tried it with pipes and also with start /b, but I haven't an idea how to transfer the CTRL-C to different cmd instance.


jeb

dbenham
Expert
Posts: 2388
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: programmatically "press" Ctrl-C / Exit batch inside CALL

#8 Post by dbenham » 25 Aug 2014 06:10

jeb wrote:I tried a bit to use CTRL-C for another cmd.exe thread, but currently all my attempts fail.

I tried it with pipes and also with start /b, but I haven't an idea how to transfer the CTRL-C to different cmd instance.
Very mysterious :? :!:

I also failed with CMD /C and pipes. Of course, if one fails, than so too should the other. But I succeeded with START /B /WAIT.
Edit: Wrong! START /B /WAIT Fails as well :oops:

Here is TEST2.BAT that launches my TEST.BAT from prior post in various ways.

Code: Select all

@echo off
echo(
echo launching via CMD /C ...
cmd /c test.bat
echo Returned %errorlevel%

echo(
echo launching via pipe ...
echo OK | test.bat
echo Returned %errorlevel%

echo(
echo launching via START /B /WAIT ...
start "" /b /wait test.bat
echo Returned %errorlevel% NEVER REACHED

Sample output

Code: Select all

C:\test>test2

launching via CMD /C ...
test=AFTER sub2 2nd SETLOCAL
Returned 255

launching via pipe ...
test=AFTER sub2 2nd SETLOCAL
Returned 255

launching via START /B /WAIT ...
test=AFTER sub2 2nd SETLOCAL

C:\test>echo %errorlevel%
-1073741510

C:\test>

Why on earth do CMD /C and the pipe transform the ERRORLEVEL to 255 :?: :?
This is especially puzzling because CMD /C was used to "press" Ctrl-C in the first place :!:

START /B /WAIT appears to work, but in reality it hasn't returned to the originating CMD session yet. Issuing EXIT returns and the calling script resumes.


Dave Benham
Last edited by dbenham on 25 Aug 2014 22:16, edited 1 time in total.

penpen
Expert
Posts: 1859
Joined: 23 Jun 2013 06:15
Location: Germany

Re: programmatically "press" Ctrl-C / Exit batch inside CALL

#9 Post by penpen » 25 Aug 2014 16:08

dbenham wrote:You can see that START /B /WAIT works, although I'm a bit surprised it does not prompt to see if you want to terminate or not.

Are you sure? Try 'exit'; this happens on WinXP home:

Code: Select all

Z:\>test2.bat

launching via CMD /C ...
Returned 255

launching via pipe ...
Returned 255

launching via START /B /WAIT ...

Z:\>exit
^CBatchvorgang abbrechen (J/N)? n
Returned -1073741510 NEVER REACHED
Z:\>

The same behaviour when using 'exit /B', but it changes the errorlevel, if you specify one:

Code: Select all

(...)
launching via START /B /WAIT ...

Z:\>exit /B 2
^CBatchvorgang abbrechen (J/N)? n
Returned 2 NEVER REACHED
Z:\>

penpen

dbenham
Expert
Posts: 2388
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: programmatically "press" Ctrl-C / Exit batch inside CALL

#10 Post by dbenham » 25 Aug 2014 22:17

Thanks penpen. You are absolutely correct, and jeb was correct all along (of course). I've corrected my prior post.


Dave Benham

Post Reply