Sign in to follow this  
Followers 0
fly

Need help getting a return code from a process using only Run...

12 posts in this topic

I have a process that I'm calling via Run so that I can get StdoutRead info from it. After the process is complete, how could I somehow check the exit code to make sure it actually finished okay?

-or-

How could I get StdoutRead info from a process using RunWait?

Thanks for any help guys!

Share this post


Link to post
Share on other sites



I have a process that I'm calling via Run so that I can get StdoutRead info from it. After the process is complete, how could I somehow check the exit code to make sure it actually finished okay?

-or-

How could I get StdoutRead info from a process using RunWait?

Thanks for any help guys!

Hi, what about starting a batch file and get the errorlevel with echo %errorlevel%?

So long,

Mega


Scripts & functions Organize Includes Let Scite organize the include files

Yahtzee The game "Yahtzee" (Kniffel, DiceLion)

LoginWrapper Secure scripts by adding a query (authentication)

_RunOnlyOnThis UDF Make sure that a script can only be executed on ... (Windows / HD / ...)

Internet-Café Server/Client Application Open CD, Start Browser, Lock remote client, etc.

MultipleFuncsWithOneHotkey Start different funcs by hitting one hotkey different times

Share this post


Link to post
Share on other sites

Just posted a solution here in Script'n'Scraps.

Share this post


Link to post
Share on other sites

Just posted a solution here in Script'n'Scraps.

Wow, thanks!

Share this post


Link to post
Share on other sites

Okay what am I doing wrong here?

$runScan = Run(@ComSpec & ' /c "' & $datastore & "\" & GUICtrlRead($userCombo) & '\USMT\scanstate.exe" ' & $datastore & "\" & GUICtrlRead($userCombo) & " /user:" & $domain & "\" & GUICtrlRead($userCombo) & " " & $scanSwitch, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
    $handle = _ProcessOpenHandle($runScan)

    
    While ProcessExists($runscan)
        Sleep(10)
    WEnd
    $exitCode = _ProcessGetExitCode($runScan, $handle)
    MsgBox(0, "", $exitCode)

I always get an exit code of 0. Is it cause I'm actually launching a program called scanstate? Cause it appears that its only getting the PID of CMD.EXE and not the actual scanstate.exe program. I tried taking out the ComSpec part, so that CMD isn't launched, but it just errors out.

Wasn't sure if I should post this question here or in the Scripts thread...

Share this post


Link to post
Share on other sites

Hmmm, I must be doing something wrong here. I even changed it to this and I still get an exit code of 0.

$runScan = Run(@ComSpec & ' /c "' & $datastore & "\" & GUICtrlRead($userCombo) & '\USMT\scanstate.exe" ' & $datastore & "\" & GUICtrlRead($userCombo) & " /user:" & $domain & "\" & GUICtrlRead($userCombo) & " " & $scanSwitch, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
    While Not ProcessExists("scanstate.exe")
        Sleep(10)
    WEnd
    $runScan = ProcessExists("scanstate.exe")
    $handle = _ProcessOpenHandle($runScan)

    
    While ProcessExists($runscan)
        Sleep(10)
    WEnd
    $exitCode = _ProcessGetExitCode($runScan, $handle)
    MsgBox(0, "", $exitCode)

Share this post


Link to post
Share on other sites

Okay what am I doing wrong here?

$runScan = Run(@ComSpec & ' /c "' & $datastore & "\" & GUICtrlRead($userCombo) & '\USMT\scanstate.exe" ' & $datastore & "\" & GUICtrlRead($userCombo) & " /user:" & $domain & "\" & GUICtrlRead($userCombo) & " " & $scanSwitch, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
    $handle = _ProcessOpenHandle($runScan)

    
    While ProcessExists($runscan)
        Sleep(10)
    WEnd
    $exitCode = _ProcessGetExitCode($runScan, $handle)
    MsgBox(0, "", $exitCode)

I always get an exit code of 0. Is it cause I'm actually launching a program called scanstate? Cause it appears that its only getting the PID of CMD.EXE and not the actual scanstate.exe program. I tried taking out the ComSpec part, so that CMD isn't launched, but it just errors out.

Wasn't sure if I should post this question here or in the Scripts thread...

Your example code above looks correct. And Yes, you are testing CMD for exitcode. If CMD has exited with 0 and the program scanstate.exe has exited with non 0, then you either need to change youe command to read the %errorlevel% of scanstate.exe and use Exit %errorlevel%, ... or You use ProcessExists directly after the Run() command to return the PID of scanstate.exe so you can get the exitcode directly from it.

Ensure that the PID that you are getting the exitcode from has indeed exited for successful output of exitcode.

Share this post


Link to post
Share on other sites

But scanstate isn't exiting with a return code of 0. If my code is right, then something isn't working.

Previously, I used:

$runscan = RunWait(@ComSpec & ' /c "' & $datastore & "\" & GUICtrlRead($userCombo) & '\USMT\scanstate.exe" ' & $datastore & "\" & GUICtrlRead($userCombo) & " /user:" & $domain & "\" & GUICtrlRead($userCombo) & " " & $scanSwitch)
    If $runscan = 0 Then 
        usmtLog("Scanstate completed successfully")
    Else
        usmtLog("ERROR " & $runscan & " - Scanstate failed to complete" & @CRLF) 
        Return("Scanstate failed to complete.")
    EndIf

and if I closed the DOS box that popped up, it would error out. Using this new code, I don't get an error if I end the process via task manager (since no box pops up). Doing it via task manager shouldn't give it a 0 exit code, should it?

Share this post


Link to post
Share on other sites

I notice that in your command with using comspec, that you are protecting the path to the executable with double quotes, but the switches witch contain some of the same variables have no double quotes around them.

If you forcefully close comspec, then the exitcode may end up as unknown, as you did not let the task complete.

For an example of how to get the exitcode of comspec with Run() used, then you could test this to show that it can be done.

$pid = Run(@ComSpec & ' /c Exit 3')
$handle = _ProcessOpenHandle($pid)
ProcessWaitClose($pid)
$exitcode = _ProcessGetExitCode($pid, $handle)
MsgBox(0, '', $exitcode)

$handle = _ProcessOpenHandle($pid)
Func _ProcessOpenHandle($i_Pid)
; Return the process handle of a PID
    $h_Process = DllCall('kernel32.dll', _
            'ptr', 'OpenProcess', _
            'int', 0x400, _
            'int', 0, _
            'int', $i_Pid)
    If Not @error Then Return $h_Process
    Return Not SetError(1)
EndFunc

Func _ProcessGetExitCode($i_Pid, $h_Process, $i_ProcessCloseHandle = 1)
; Return Process Exitcode of a Process Handle and close Handle as default
    Local $i_ExitCode, $v_Placeholder, $i_Error = 0
    If ProcessExists($i_Pid) Then
        $i_Error = 3
    Else
        If IsArray($h_Process) Then
            $i_ExitCode = DllCall('kernel32.dll', _
                    'ptr', 'GetExitCodeProcess', _
                    'ptr', $h_Process[0], _
                    'int_ptr', $v_Placeholder)
            If @error Then $i_Error = 1
        EndIf
    EndIf
; Close the process handle of a PID
    If $i_Error = 4 Or $i_ProcessCloseHandle Then
        DllCall('kernel32.dll', _
                'ptr', 'CloseHandle', _
                'ptr', $h_Process)
        If @error Then $i_Error = $i_Error + 2
    EndIf
    If $i_Error Then Return Not SetError($i_Error)
    Return $i_ExitCode[2]
EndFunc

You may still need to tell comspec to exit with %errorlevel% or to monitor scanstate.exe PID directly by using ProcessExists() to get the PID of scanstate.exe and act on the PID.

Share this post


Link to post
Share on other sites

I notice that in your command with using comspec, that you are protecting the path to the executable with double quotes, but the switches witch contain some of the same variables have no double quotes around them.

I have in some of my comments: ; Doesn't work with quotes around datastore. I have no idea why. The same batch file works fine.

If you forcefully close comspec, then the exitcode may end up as unknown, as you did not let the task complete.

Using the alternate method I posted with RunWait, closing via task manager did not result in a return code of 0. hmmm

For an example of how to get the exitcode of comspec with Run() used, then you could test this to show that it can be done.

$pid = Run(@ComSpec & ' /c Exit 3')
$handle = _ProcessOpenHandle($pid)
ProcessWaitClose($pid)
$exitcode = _ProcessGetExitCode($pid, $handle)
MsgBox(0, '', $exitcode)

$handle = _ProcessOpenHandle($pid)
Func _ProcessOpenHandle($i_Pid)
; Return the process handle of a PID
    $h_Process = DllCall('kernel32.dll', _
            'ptr', 'OpenProcess', _
            'int', 0x400, _
            'int', 0, _
            'int', $i_Pid)
    If Not @error Then Return $h_Process
    Return Not SetError(1)
EndFunc

Func _ProcessGetExitCode($i_Pid, $h_Process, $i_ProcessCloseHandle = 1)
; Return Process Exitcode of a Process Handle and close Handle as default
    Local $i_ExitCode, $v_Placeholder, $i_Error = 0
    If ProcessExists($i_Pid) Then
        $i_Error = 3
    Else
        If IsArray($h_Process) Then
            $i_ExitCode = DllCall('kernel32.dll', _
                    'ptr', 'GetExitCodeProcess', _
                    'ptr', $h_Process[0], _
                    'int_ptr', $v_Placeholder)
            If @error Then $i_Error = 1
        EndIf
    EndIf
; Close the process handle of a PID
    If $i_Error = 4 Or $i_ProcessCloseHandle Then
        DllCall('kernel32.dll', _
                'ptr', 'CloseHandle', _
                'ptr', $h_Process)
        If @error Then $i_Error = $i_Error + 2
    EndIf
    If $i_Error Then Return Not SetError($i_Error)
    Return $i_ExitCode[2]
EndFunc

You may still need to tell comspec to exit with %errorlevel% or to monitor scanstate.exe PID directly by using ProcessExists() to get the PID of scanstate.exe and act on the PID.

Can you explain this a little more? What does the exit 3 do in the comspec? I also tried getting the PID of scanstate.exe directly, but that didn't help either.

Thank you SO MUCH for all the help man.

Share this post


Link to post
Share on other sites

Can you explain this a little more? What does the exit 3 do in the comspec? I also tried getting the PID of scanstate.exe directly, but that didn't help either.

I have done similar with scanstate below. The Exit 3 was to make comspec return an exitcode of 3 for the AutoIt script test to retrieve. I am getting a return exitcode of 0 for success and 1 for error. Does seem different to code number of errorlevel for some reason.

I have added some comments into the code to mention the steps.

; run scanstate
$pid = Run('scanstate.exe /all ' & @HomeDrive & '\SS_OutPut', '', @SW_HIDE, 2)

; get the process handle immediately
$handle = _ProcessOpenHandle($pid)

; get the stdout data
Global $data
While 1
    $data &= StdOutRead($pid)
    If @error Then ExitLoop
WEnd

; need to ensure process has exited before checking exitcode
ProcessWaitClose($pid)

; check exitcode with the process handle and then close handle
$exitcode = _ProcessGetExitCode($pid, $handle)

; show stdout data
MsgBox(0, '$data', $data)

; show exitcode
MsgBox(0, '$exitcode', $exitcode)

Exit

Func _ProcessOpenHandle($i_Pid)
; Return the process handle of a PID
    $h_Process = DllCall('kernel32.dll', _
            'ptr', 'OpenProcess', _
            'int', 0x400, _
            'int', 0, _
            'int', $i_Pid)
    If Not @error Then Return $h_Process
    Return Not SetError(1)
EndFunc

Func _ProcessGetExitCode($i_Pid, $h_Process, $i_ProcessCloseHandle = 1)
; Return Process Exitcode of a Process Handle and close Handle as default
    Local $i_ExitCode, $v_Placeholder, $i_Error = 0
    If ProcessExists($i_Pid) Then
        $i_Error = 3
    Else
        If IsArray($h_Process) Then
            $i_ExitCode = DllCall('kernel32.dll', _
                    'ptr', 'GetExitCodeProcess', _
                    'ptr', $h_Process[0], _
                    'int_ptr', $v_Placeholder)
            If @error Then $i_Error = 1
        EndIf
    EndIf
; Close the process handle of a PID
    If $i_Error = 4 Or $i_ProcessCloseHandle Then
        DllCall('kernel32.dll', _
                'ptr', 'CloseHandle', _
                'ptr', $h_Process)
        If @error Then $i_Error = $i_Error + 2
    EndIf
    If $i_Error Then Return Not SetError($i_Error)
    Return $i_ExitCode[2]
EndFunc

Share this post


Link to post
Share on other sites

I have done similar with scanstate below. The Exit 3 was to make comspec return an exitcode of 3 for the AutoIt script test to retrieve. I am getting a return exitcode of 0 for success and 1 for error. Does seem different to code number of errorlevel for some reason.

I have added some comments into the code to mention the steps.

; run scanstate
$pid = Run('scanstate.exe /all ' & @HomeDrive & '\SS_OutPut', '', @SW_HIDE, 2)

; get the process handle immediately
$handle = _ProcessOpenHandle($pid)

; get the stdout data
Global $data
While 1
    $data &= StdOutRead($pid)
    If @error Then ExitLoop
WEnd

; need to ensure process has exited before checking exitcode
ProcessWaitClose($pid)

; check exitcode with the process handle and then close handle
$exitcode = _ProcessGetExitCode($pid, $handle)

; show stdout data
MsgBox(0, '$data', $data)

; show exitcode
MsgBox(0, '$exitcode', $exitcode)

Exit

Func _ProcessOpenHandle($i_Pid)
; Return the process handle of a PID
    $h_Process = DllCall('kernel32.dll', _
            'ptr', 'OpenProcess', _
            'int', 0x400, _
            'int', 0, _
            'int', $i_Pid)
    If Not @error Then Return $h_Process
    Return Not SetError(1)
EndFunc

Func _ProcessGetExitCode($i_Pid, $h_Process, $i_ProcessCloseHandle = 1)
; Return Process Exitcode of a Process Handle and close Handle as default
    Local $i_ExitCode, $v_Placeholder, $i_Error = 0
    If ProcessExists($i_Pid) Then
        $i_Error = 3
    Else
        If IsArray($h_Process) Then
            $i_ExitCode = DllCall('kernel32.dll', _
                    'ptr', 'GetExitCodeProcess', _
                    'ptr', $h_Process[0], _
                    'int_ptr', $v_Placeholder)
            If @error Then $i_Error = 1
        EndIf
    EndIf
; Close the process handle of a PID
    If $i_Error = 4 Or $i_ProcessCloseHandle Then
        DllCall('kernel32.dll', _
                'ptr', 'CloseHandle', _
                'ptr', $h_Process)
        If @error Then $i_Error = $i_Error + 2
    EndIf
    If $i_Error Then Return Not SetError($i_Error)
    Return $i_ExitCode[2]
EndFunc
Thanks for all the help man. it works now!

Share this post


Link to post
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
Sign in to follow this  
Followers 0