Jump to content

Run() and get returned errorlevel


Recommended Posts

I'm trying to set a timer on externally run programs and need the return value:

Func fnRun($var, $delay = 180)
    $retVal = Run($var)
    for $i = 1 to $delay
        if ProcessExists($retVal) = 0 Then
            ; process has completed
            Return(0)
        EndIf
        Sleep(1000)
    Next
EndFunc

Is there a way to read %errorlevel% once the run has completed?

I can't use RunWait because the external program may hang, suspending the script.

Thanks

Link to comment
Share on other sites

Well in your case you have it set to return(0), try changing it from 0 to 1 and it will return a 1 if it is running.

If you're trying to wait until the process is running I would use a Do-Until statement; it should get the job done.

Link to comment
Share on other sites

Func fnRun($var, $delay = 180)
    $retVal = Run($var)
    for $i = 1 to $delay
        If $retVal Then ; If success
            ; process has completed
            Return(0)
        EndIf
        Sleep(1000)
    Next
EndFunc

Else make your own indicator

Func fnRun($var, $delay = 180)
Global $processRunning=0
    $retVal = Run($var)
    for $i = 1 to $delay
        If ProcessExists($var) Then
   ; process has completed
   $processRunning=1
            Return(0)
        ElseIf Not ProcessExists($var) Then
   ; process has not been completed
   $processRunning=0
  EndIf
        Sleep(1000)
    Next
EndFunc
Edited by vfear
Link to comment
Share on other sites

The RunWait() function simply runs and it waits until the process is open, so in reality the DoUntil statement will not work. Now for instance, the Run() function would work in this case with the DoUntil statement because you would be checking to see if the process was ran and you have your own control over it inside the code block.

Func fnRun($var)
    $retVal = Run($var)
Do
; Do code
Until Not ProcessExists($var)
EndFunc

Link to comment
Share on other sites

At the risk of sounding repetitive, I need the errorlevel of the program ($var) when it exits and if it doesn't exit, return after a timeout so the script can continue. The above code will not give me the errorlevel.

I need the functionality of my first post but to be able to return the errorlevel as well.

Link to comment
Share on other sites

Try this:

MsgBox(0, "Example 1", fnRun("xcopy.exe"))  ; xcopy returns an errorlevel of 4
MsgBox(0, "Example 2", fnRun("xcopy.exe /c /y C:\windows\temp\*.log c:\windows\temp2\"))    ; xcopy returns an errorlevel of 0 because it successfully completed
 
Exit
 
Func fnRun($var, $delay = 180)
    $retVal = RunWait($var)
    Return $retVal
EndFunc

The above example behaves properly (I'm using a custom program, not xcopy) however if $var freezes then the script will never continue.

So how do I achieve the above and be able to continue the script if $var freezes?

Edited by readmedottxt
Link to comment
Share on other sites

I'm not trying to be rude - what your program will do is return a '1' when the process still exists and return a '0' when the process doesn't.

What it wont return is the errorlevel of the process when it exits.

What mine does is returns the errorlevel of the exiting process. Yours does not return the errorlevel, your function returns a code if the process still exists. I also don't understand what the purpose of the For|Next loop in your code is, as it cannot loop because the first two lines will ensure it exits no matter what.

I need to return the errorlevel within the function

Link to comment
Share on other sites

fnRun($var)

If @error Then

    ; do something

EndIf

Func fnRun($var)

    Local $retVal = Run($var)

    If $retVal Then

        Do

            Sleep(1000)

        Until Not ProcessExists($retVal)

        Return SetError(0)

    Else

        Return SetError(-1)

    EndIf

EndFunc

edit

whew - code tags are not what they use to be.

Edited by ripdad

"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Link to comment
Share on other sites

On second thought -- your first post will do okay -- timer wise.

fnRun($var, 180)

If @error Then

; do something

EndIf

Func fnRun($var, $delay = 180)

Local $retVal = Run($var)

for $i = 1 to $delay

If Not ProcessExists($retVal) Then

Return SetError(0)

EndIf

Sleep(1000)

Next

Return SetError(-1)

EndFunc

"The mediocre teacher tells. The Good teacher explains. The superior teacher demonstrates. The great teacher inspires." -William Arthur Ward

Link to comment
Share on other sites

So, let me understand you. You want the exit code of the $var process to return to your calling function... unless there is a timeout.

The documentation on Run() and RunWait() indicate two different values being returned.

Runwait() Return Value:

Success: Returns the exit code of the program that was run.

Failure: Returns 0 and sets @error to non-zero.

Run() Return Value:

Success: The PID of the process that was launched.

Failure: Returns 0 and sets @error to non-zero.

You can't get the exit code of the process with Run().

The best you can do using only AutoIt is to launch a second script from within the first script.

Your first script would launch the second script with Run(), passing $var as a command line parameter, then monitor the other script, looking for it's execution to stop and to get the exit code data from that script; or for a timeout exception.

The second script would launch the $var process with RunWait() then send $var's exit code back to the first script through a communication mechanism outside of Return(), as your first script has no way to get the second script's exit code via that mechanism. A simple filewrite with the exit code is an quick cludge, but there are other inter-script communication methods that could be used as well.

Hope this helps.

Edited by VeryGary
Link to comment
Share on other sites

I actually asked a similar question recently. I wanted a process exit code (or "errorlevel") while also checking it's output with StdoutRead. Give some of this code a try.

#include <WinAPI.au3>
 
Global Const $PROCESS_QUERY_INFORMATION = 0x0400
 
$iPID = Run('YourCommand.exe')
$hPID = _WinAPI_OpenProcess($PROCESS_QUERY_INFORMATION, 0, $iPID)
 
While ProcessExists($iPID)
    Sleep(10)
WEnd
 
ConsoleWrite(_ProcessGetExitCode($hPID))
_WinAPI_CloseHandle($hPID)
 
Func _ProcessGetExitCode($hProc) ;Get process exit code from handle
    Local $t_ExitCode = DllStructCreate('int')
    Local $avRET = DllCall('kernel32.dll', 'int', 'GetExitCodeProcess', 'ptr', $hProc, 'ptr', DllStructGetPtr($t_ExitCode))
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return DllStructGetData($t_ExitCode, 1)
    EndIf
EndFunc
Edited by therks
Link to comment
Share on other sites

I don't believe any of the code above will achieve what the OP is after.

I think the goal is to run a script and return immediately returning the PID, and continue the rest of the script without a loop waiting for the process to end.

I'm not familiar with the code above (therks) could possibly work if the rest of the code is present within a loop.

#include <WinAPI.au3>
 
 
 
Global Const $PROCESS_QUERY_INFORMATION = 0x0400
 
$iPID = Run('YourCommand.exe')
$hPID = _WinAPI_OpenProcess($PROCESS_QUERY_INFORMATION, 0, $iPID)
 
While ProcessExists($iPID)
    $WeWantThis = _ProcessGetExitCode($hPID)
    If Not @error Then
            MsgBox(0,0,$WeWantThis)
            _WinAPI_CloseHandle($hPID)
    EndIf
    _TheRestOfYourScriptFunc()
    Sleep(10)
WEnd
 
 
Func _ProcessGetExitCode($hProc) ;Get process exit code from handle
    Local $t_ExitCode = DllStructCreate('int')
    Local $avRET = DllCall('kernel32.dll', 'int', 'GetExitCodeProcess', 'ptr', $hProc, 'ptr', DllStructGetPtr($t_ExitCode))
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return DllStructGetData($t_ExitCode, 1)
    EndIf
EndFunc
 
Func _TheRestOfYourScriptFunc()
       ;your code
       ;_funca()
       ;_funcb()
EndFunc

EDIT:

You will want to stop this part of the procedure once you have your return

$WeWantThis = _ProcessGetExitCode($hPID)

So you'll have to jiggle it a little obviously.

Edited by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

JohnOne, He's not looking for any PID, he's looking for the return code from the Run()'d executable, as indicated by the following:

Is there a way to read %errorlevel% once the run has completed?

What I need to know is how to get the returned errorlevel without using a RunWait which suspends the script until the external program completes.

Sorry, I may not have been clear. I wish to get the errorlevel of $var when it exits.

Here is the equivalent code with RunWait

RunWait returns the exit code of the process, not the PID. All this talk of PIDs is irrelevant and confusing the situation. When a program is called from cmd.exe and exits it returns an exit code to the shell which is assigned to the environment variable %errorlevel%.

therks solution is much cleaner than mine.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...