I have a batch file that needs to be run in a 32-bit context so contains a bit of code to call the 32-bit command processor with its own path. This script also needs to be able to return error code on failure which it does via exit /b 123
. However...
When the exit
is in a (
)
block, AND contains any statement after it, this does not get returned correctly.
@echo off
setlocal EnableDelayedExpansion
rem Ensure we're running in 32-bit mode
if not %PROCESSOR_ARCHITECTURE%==x86 (
echo Thunking to 32-bit mode
%Windir%\SysWOW64\cmd.exe /c %0
echo !ERRORLEVEL!
exit /b !ERRORLEVEL!
)
(
echo before
exit /b 456
echo after
)
The output is as follows:
H:\>sub.bat
Thunking to 32-bit mode
before
0
H:\>
If you remove the echo
after the exit
, then it works exactly as expected.
H:\>sub.bat
Thunking to 32-bit mode
before
456
H:\>
Even if you replace the echo
with a rem
or any other command, it still fails. If you manually run the 32-bit cmd.exe
and run the same script, the exit code gets set correctly.
H:\>sub.bat
before
H:\>echo %ERRORLEVEL%
456
H:\>
Can anyone give an explanation and a workaround for this?
EXIT /b has the option to set a specific exit code, EXIT /b 0 for sucess, EXIT /b 1 (or greater) for an error. The exit code can be an integer of up to 10 digits in length (positive or negative). EXIT without an ExitCode acts the same as goto:eof and will not alter the ERRORLEVEL.
EXIT /B at the end of the batch file will stop execution of a batch file. use EXIT /B < exitcodes > at the end of the batch file to return custom return codes. Environment variable %ERRORLEVEL% contains the latest errorlevel in the batch file, which is the latest error codes from the last command executed.
Check the errorlevel in an if statement, and then exit /b (exit the batch file only, not the entire cmd.exe process) for values other than 0.
Exit syntax Quits the CMD. EXE program (command interpreter) or the current batch script. Specifies to exit the current batch script instead of CMD. EXE.
The use of the /b switch in the "else" part of the script is causing the exit code to be lost by the second instance of cmd.exe.
When the second instance of the batch file is executed from Syswow64, it will be exiting with the code of 456. Its parent cmd.exe will receive this exit code but has no interest in preserving it. The cmd.exe was able to successfully run the batch and thus exits with 0, back to the first instance.
If you omit the /b switch in the "else" part of the script, this forces the batch file to quit its parent cmd.exe, rather than just finish processing. As the cmd.exe is then told to quit with the 456 exit code, this will be preserved.
The help text for "exit" does infer this behaviour, but it doesn't seem very obvious until you read it with this in mind!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With