%=ExitCode% not updated with a final EXIT /B in sub routine

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
aGerman
Expert
Posts: 4744
Joined: 22 Jan 2010 18:01
Location: Germany

%=ExitCode% not updated with a final EXIT /B in sub routine

#1 Post by aGerman » 10 Aug 2014 04:38

Recently I found that %=ExitCode% was only updated if an application returns. It seems not to be updated if you quit an internal procedure using exit /b. That could be a possibility to return 2 values at once.
Is it just me (Win7 x86) or can anybody out there confirm that behavior?

Code: Select all

@echo off &setlocal
call :proc
set /a "x=0x%=ExitCode%, y=%errorlevel%"
echo %x%
echo %y%
pause
goto :eof

:proc
cmd /c exit /b 1
exit /b 2

1
2
Drücken Sie eine beliebige Taste . . .

Regards
aGerman

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#2 Post by foxidrive » 10 Aug 2014 04:40

Win 8.1 32 bit

Code: Select all

1
2
Press any key to continue . . .

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

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#3 Post by aGerman » 10 Aug 2014 04:42

Thanks foxi.
Strange isn't it :D

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#4 Post by foxidrive » 10 Aug 2014 04:53

I'm getting old - I can't even remember what %=ExitCode% was good for. :D

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

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#5 Post by aGerman » 10 Aug 2014 05:16

It should contain the errorlevel as 8 digit hex string as far as I understood.

Small example of how to use the above.

Code: Select all

@echo off &setlocal
call :getPETarget "%SystemRoot%\explorer.exe"
echo Windows Explorer: %errorlevel% %=ExitCode%
pause
goto :eof


:getPETarget FilePath
setlocal DisableDelayedExpansion
set "File=%~1"
set Cmp="%temp%\%random%.%random%.1kB"
set Dmp="%temp%\%random%.%random%.dmp"

if exist "%File%" (
  >%Cmp% (
    for /l %%i in (1 1 32) do <nul set /p "=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  )
  setlocal EnableDelayedExpansion
) else (endlocal &cmd /c exit /b 0 &exit /b 1) &REM File Not Found

set "X=1"
>!Dmp! (
  for /f "skip=1 tokens=1,2 delims=: " %%i in ('fc /b "!File!" !Cmp!^|findstr /vbi "FC:"') do (
    set /a Y=0x%%i
    for /l %%k in (!X! 1 !Y!) do echo 41
    set /a X=Y+2
    echo %%j
  )
)
del !Cmp!

set "err="
<!Dmp! (
  set /p "A="
  set /p "B="
  if "!A!!B!" neq "4D5A" (set /a err=2 &REM.Wrong Magic Number) else (
    for /l %%i in (3 1 60) do set /p "="
    set /p "C="
    set /p "D="
    set /p "E="
    set /p "F="
    if 0x!F!!E!!D!!C! lss 1 (set /a err=3 &REM.Out Of Scope) else (
      if 0x!F!!E!!D!!C! gtr 1018 (set /a err=3 &REM.Out Of Scope) else (
        for /l %%i in (65 1 0x!F!!E!!D!!C!) do set /p "="
        set /p "G="
        set /p "H="
        set /p "I="
        set /p "J="
        set /p "K="
        set /p "L="
      )
    )
  )
)

del !Dmp!
if defined err (endlocal &endlocal &cmd /c exit /b 0 &exit /b %err%)

if "%G%%H%%I%%J%"=="50450000" (
  set /a Prcr=0x%L%%K%
) else (endlocal &endlocal &cmd /c exit /b 0 &exit /b 4) &REM No PE File
endlocal &endlocal &cmd /c exit /b %Prcr% &exit /b 0

That code will determine the target processor of a PE file. That way you can see if it is a 32 or 64 Bit executable (and in case of explorer.exe you also know if you run a 32 or 64 Bit OS).
Errorlevel:
0 success
1 file not found
2 wrong magic number
3 out of scope (not part of the first 1kB in the executable)
4 not a PE file format

=ExitCode
CPU specifier (should be 0x014C for 32Bit and 0x8664 for 64Bit according to the specification)

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#6 Post by foxidrive » 10 Aug 2014 05:32

Here is the result.

Code: Select all

Windows Explorer: 0 0000014C
Press any key to continue . . .


That's interesting.

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

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#7 Post by aGerman » 10 Aug 2014 05:41

For testing purposes I compiled a 64Bit app where the code returns
0 00008664

I also passed other different binary files where it returns e.g.
2 00000000

Seems to work just fine but certainly needs some further investigations :wink:

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

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#8 Post by dbenham » 10 Aug 2014 08:03

That has always been my understanding - %=ExitCode% and %=ExitCodeAscii% only report the return code for applications (external comands). It does not work with batch sub-routines (or called batch scripts for that matter). You can use either EXIT or EXIT /B with your CMD /C line to set the value.

%=ExitCode% is the return code in hex format
%=ExitCodeAscii% is the string value of the returned ASCII code. It only works with codes between 32 - 127 inclusive.

But, I hadn't thought of using the behavior as a way of returning two values :!:
Good idea :idea: :D


Addendum: I believe that EXIT /B never sets the process return code directly. It sets the %ERRORLEVEL%, which is a CMD.EXE internal value. When the CMD.EXE process terminates, it passes on the current value of %ERRORLEVEL% as the process return code. That is my understanding anyway.


Dave Benham

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

Re: %=ExitCode% not updated with a final EXIT /B in sub rout

#9 Post by aGerman » 10 Aug 2014 08:13

dbenham wrote:That has always been my understanding - %=ExitCode% and %=ExitCodeAscii% only report the return code for applications (external comands).

Good to know :!: I thought that errorlevel, =ExitCode and =ExitCodeAscii were always somehow related things. Now I realized that you can set the values independently.

dbenham wrote:Good idea :idea: :D

Thanks :D

dbenham wrote:I believe that EXIT /B never sets the process return code directly. It sets the %ERRORLEVEL%, which is a CMD.EXE internal value. When the CMD.EXE process terminates, it passes on the current value of %ERRORLEVEL% as the process return code. That is my understanding anyway.

I see. Thanks for the explanation. It fully answers my question :D


Regards
aGerman

Post Reply