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?
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!