1

I have one single Batch file with 2 functions in it:
1.) MAIN
2.) ASYNC

Now i try to call the ASYNC function out of the MAIN function without waiting for the completion of the ASYNCfunction. Is that possible?
Here is my Batch file:

@echo off
:MAIN
setlocal
echo Here i am in the Main Thread
start /b :ASYNC
echo Here i am in the Main Thread again
endlocal
exit /b 0

:ASYNC
setlocal
echo I am in the ASYNC Thread
timeout /T 100
endlocal
exit /b 0

Is there any possibility to run a function in a single batchfile asynchron from another function in the same batchfile without separating the functions to multiple files?

Greets & Thank you :D

Felix Waltl
  • 129
  • 6
  • Yes, change `start /b :ASYNC` to `start "" /B cmd /D /C call "%~f0" :ASYNC`, then insert before `:MAIN` the line `if not "%~1"=="" goto %~1`, but note, that `:ASYNC` becomes executed in a new `cmd.exe` instance then… – aschipfl Aug 25 '22 at 19:54
  • Or as a better but more complex method: replace `start /b :ASYNC` by `start "" /B cmd /D /C "%~d0\:ASYNC:\..%~dpn0" %*` and insert before `:MAIN` the line `for /F "tokens=3 delims=:" %%Z in ("%~0") do goto :%%Z`… – aschipfl Aug 25 '22 at 20:00

1 Answers1

0

Yes, there is a possibility: use start to let the script restart itself, provide the label of the sub-routine as an argument and use goto rather than call to continue execution at that point:

@echo off
if not "%~1"=="" goto %~1
:MAIN
setlocal
echo Here I am in the MAIN thread
start "" /B cmd /D /C "%~f0" :ASYNC
echo Here I am in the MAIN thread again
endlocal
exit /b 0

:ASYNC
setlocal
echo Now I am in the ASYNC thread
timeout /T 10
endlocal
exit /b 0

When you run the script and want to first execute the main section, you must not provide an argument. If you do, it will be interpreted as a jump label. To avoid that, you could check whether the (first) argument begins with a : and skip the goto if not. Replace the line if not "%~1"=="" goto %~1 by the following to achieve that:

set "ARG1=%~1" & if not defined ARG1 shift /1 & goto :MAIN
if "%ARG1:~,1%"==":" goto %ARG1%

This is not absolutely safe against any odd arguments (like "&"&), but it will serve well in most situations. However, regard that the argument positions may not be as expected, because of the additional label argument (check out the argument string %*, which is even not going to be affected by shift).

Note, that the sub-routine then becomes executed in a new cmd.exe instance, so any environment changes will not reach the main instance.


There is even a better way to accomplish what you want, without affecting any potential arguments, namely to embed the label of the sub-routine in the script path itself when restarting the script (technique courtesy of user jeb, see his answer to How to pipe the final result of a windows batch for loop into another command):

@echo off
for /F "tokens=3 delims=:" %%Z in ("%~0") do goto :%%Z
:MAIN
setlocal
echo Here I am in the MAIN thread
start "" /B cmd /D /C "%~d0\:ASYNC:\..%~pnx0" %*
echo Here I am in the MAIN thread again
endlocal
exit /b 0

:ASYNC
setlocal
echo Now I am in the ASYNC thread
timeout /T 10
endlocal
exit /b 0

The key portion is the augmented path string %~d0\:ASYNC:\..%~pnx0, which is going to be resolved to %~d0%~pnx0 (that is the full script path %~0).

The sub-routine becomes again executed in a new cmd.exe instance.

aschipfl
  • 33,626
  • 12
  • 54
  • 99