User Tools

Site Tools


waiting_20for_20an_20external_20program_20to_20terminate

Waiting for an external program to terminate

by Richard Russell, June 2006

The *RUN command (or, equivalently, the OSCLI “RUN” statement) executes a specified external application and (by default) waits for the application to terminate before returning control to your BASIC program. This is often what is required: for example if the external application creates a file you probably don't want to continue execution of your BASIC program until the file has been created.

This is fine when *RUN does what you need, but on occasion you may need to use the additional facilities provided by the ShellExecute Windows API function. In particular ShellExecute allows you to specify the working directory used by the external application and to specify the show state of that application's window. For example it allows you to run the application in a hidden window, which may well be useful when you don't want the user to be troubled by the appearance of another window.

The syntax of the ShellExecute function when used for this purpose is as follows:

        SYS "ShellExecute", @hwnd%, 0, prog$, parm$, cdir$, show%

Here prog$ is the name of the application you want to run (e.g. ““NOTEPAD.EXE””), parm$ contains the command line parameters for the application, if any (in the case of an editor like NOTEPAD that would typically be the name of the file to edit), cdir$ is the working directory you want the application to use and show% is the window's show state (e.g. 0 to hide the window, 1 to show it normally).

So you might for example use a statement such as this:

        SYS "ShellExecute", @hwnd%, 0, "notepad.exe", "test.txt", "C:\", 1

However the use of ShellExecute has one significant disadvantage compared to the use of *RUN: it does not wait until the external application has terminated. Control will be returned to your BASIC program immediately.

To overcome this disadvantage you can use the procedure listed below. This behaves like ShellExecute except that it does not return until the external application has terminated:

        DEF PROCexecuteandwait(prog$,parm$,cdir$,show%)
        LOCAL sei{}, res%
        DIM sei{cbSize%,fMask%,hwnd%,lpVerb%,lpFile%,lpParameters%,lpDirectory%,nShow%, \
        \       hInstApp%,lpIDList%,lpClass%,hkeyClass%,dwHotKey%,hIcon%,hProcess%}
        prog$ += CHR$0
        parm$ += CHR$0
        cdir$ += CHR$0
        sei.cbSize% = DIM(sei{})
        sei.fMask% = 64 : REM SEE_MASK_NOCLOSEPROCESS
        sei.hwnd% = @hwnd%
        sei.lpFile% = !^prog$
        sei.lpParameters% = !^parm$
        sei.lpDirectory% = !^cdir$
        sei.nShow% = show%
        SYS "ShellExecuteEx", sei{}
        IF sei.hProcess% = 0 THEN ENDPROC
        REPEAT
          SYS "WaitForSingleObject", sei.hProcess%, 100 TO res%
        UNTIL res%<>258 : REM WAIT_TIMEOUT
        SYS "CloseHandle", sei.hProcess%
        ENDPROC

So, by analogy with the example above, you might call this procedure as follows:

        PROCexecuteandwait("notepad.exe", "test.txt", "C:\", 1)

If you need to know the exit code (ERRORLEVEL) of the program then the above code can be converted to a function which returns this value:

        DEF FNexecuteandwait(prog$,parm$,cdir$,show%)
        LOCAL sei{}, res%
        DIM sei{cbSize%,fMask%,hwnd%,lpVerb%,lpFile%,lpParameters%,lpDirectory%,nShow%, \
        \       hInstApp%,lpIDList%,lpClass%,hkeyClass%,dwHotKey%,hIcon%,hProcess%}
        prog$ += CHR$0
        parm$ += CHR$0
        cdir$ += CHR$0
        sei.cbSize% = DIM(sei{})
        sei.fMask% = 64 : REM SEE_MASK_NOCLOSEPROCESS
        sei.hwnd% = @hwnd%
        sei.lpFile% = !^prog$
        sei.lpParameters% = !^parm$
        sei.lpDirectory% = !^cdir$
        sei.nShow% = show%
        SYS "ShellExecuteEx", sei{}
        IF sei.hProcess% = 0 THEN = 1067
        REPEAT
          SYS "WaitForSingleObject", sei.hProcess%, 100 TO res%
        UNTIL res%<>258 : REM WAIT_TIMEOUT
        SYS "GetExitCodeProcess", sei.hProcess%, ^res%
        SYS "CloseHandle", sei.hProcess%
        = res%

You might call it as follows:

        exitcode% = FNexecuteandwait("notepad.exe", "test.txt", "C:\", 1)
This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
waiting_20for_20an_20external_20program_20to_20terminate.txt · Last modified: 2018/04/14 17:24 by richardrussell