Sign in to follow this  
Followers 0
mlowery

Run (not RunWait) with DOS exit code

8 posts in this topic

This should be simple, but I'm not getting it today....

I'm doing processing on large MP3s using DOS command-line applications.

I want to run each as DOS command, using Run instead of RunWait because as soon as the process exists, I want to immediately change the priority of the process to idle so it doesn't hog the processor. After the priority is set, however, I'd like to wait until the process completes, but report the DOS exit code.

Run returns the PID instead of the errorcode like RunWait. I can use the STDERR flag with Run, but it returns error text instead of error codes.

How do I get the original numeric DOS error code when using Run instead of RunWait?

Example code below works, but I don't know how to access the actual error code. The code below returns "1" as an error code if any error text is received in the ERR channel (regardless of actual DOS error code), and "0" if nothing is in the ERR channel.

Enum $PROCESS_PRIORITY_IDLE = 0, $PROCESS_PRIORITY_BELOW_NORMAL, $PROCESS_PRIORITY_NORMAL, $PROCESS_PRIORITY_ABOVE_NORMAL, $PROCESS_PRIORITY_HIGH, $PROCESS_PRIORITY_REALTIME
Func _RunDOSPriority($sCommand, $sPath = "", $showFlag = @SW_HIDE, $waitFlag = False, $iPriority = $PROCESS_PRIORITY_NORMAL, $sIO = 0)
    Local $line, $pid   
    If $waitFlag = True Then $sIO = 4
    $pid = Run(@ComSpec & " /C " & $sCommand, $sPath, $showFlag, $sIO)  
    ProcessWait($pid)   
    If $iPriority >= $PROCESS_PRIORITY_IDLE And $iPriority <= $PROCESS_PRIORITY_REALTIME Then ProcessSetPriority($pid, $iPriority)
    If $waitFlag Then
        ProcessWaitClose($pid)
        While 1
            $line = StderrRead($pid)
            If @error Then Return 0
            Return SetError(1, 0, 1) ;if any errtxt read, then report errcode 1 (not sure how to report actual errcode as from runwait)
        WEnd
    Else
        Return $pid
    EndIf
EndFunc

Share this post


Link to post
Share on other sites



Maybe you should have a look on machine code ASM to see what byte, data represent the exit code. Then you could capture that exit code using StdoutRead

Share this post


Link to post
Share on other sites

after $line = StderrRead($pid), ConsoleWriteError($line) you might get something.

Also try using _RunDos().


Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites

The following functions I found it in AutoIt3Wrapper.au3

;===============================================================================
;
; Function Name:    _ProcessExitCode()
; Description:      Returns a handle/exitcode from use of Run().
; Parameter(s):     $i_Pid        - ProcessID returned from a Run() execution
;                   $h_Process    - Process handle
; Requirement(s):   None
; Return Value(s):  On Success - Returns Process handle while Run() is executing
;                                (use above directly after Run() line with only PID parameter)
;                              - Returns Process Exitcode when Process does not exist
;                                (use above with PID and Process Handle parameter returned from first UDF call)
;                   On Failure - 0
; Author(s):        MHz (Thanks to DaveF for posting these DllCalls in Support Forum)
;
;===============================================================================
;
Func _ProcessExitCode($i_Pid, $h_Process = 0)
    ; 0 = Return Process Handle of PID else use Handle to Return Exitcode of a PID
    Local $v_Placeholder
    If Not IsArray($h_Process) Then
        ; 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
    Else
        ; Return Process Exitcode of PID
        $h_Process = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', $v_Placeholder)
        If Not @error Then Return $h_Process[2]
    EndIf
    Return 0
EndFunc   ;==>_ProcessExitCode

Func _ProcessCloseHandle($h_Process)
    ; Close the process handle of a PID
    DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process)
    If Not @error Then Return 1
    Return 0
EndFunc   ;==>_ProcessCloseHandle

Func ShowStdOutErr($l_Handle, $ShowConsole = 1)
    Local $Line, $tot_out, $err1 = 0, $err2 = 0
    Do
        Sleep(10)
        $Line = StdoutRead($l_Handle)
        $err1 = @error
        $tot_out &= $Line
        If $ShowConsole Then ConsoleWrite($Line)
        $Line = StderrRead($l_Handle)
        $err2 = @error
        $tot_out &= $Line
        If $ShowConsole Then ConsoleWrite($Line)
    Until $err1 And $err2
    Return $tot_out
EndFunc   ;==>ShowStdOutErr

Example

#include <Constants.au3>

$Pid = Run(@ComSpec & ' /c dir /g', @WindowsDir, @SW_SHOW, $STDERR_CHILD + $STDOUT_CHILD)
$Handle = _ProcessExitCode($Pid)
ShowStdOutErr($Pid)
$ExitCode = _ProcessExitCode($Pid, $Handle)
_ProcessCloseHandle($Handle)
MsgBox(0, "Program returned with exit code:", $ExitCode)

$Pid = Run(@ComSpec & ' /c dir', @WindowsDir, @SW_SHOW, $STDERR_CHILD + $STDOUT_CHILD)
$Handle = _ProcessExitCode($Pid)
ShowStdOutErr($Pid)
$ExitCode = _ProcessExitCode($Pid, $Handle)
_ProcessCloseHandle($Handle)
MsgBox(0, "Program returned with exit code:", $ExitCode)

AutoIt Scripts:NetPrinter - Network Printer UtilityRobocopyGUI - GUI interface for M$ robocopy command line

Share this post


Link to post
Share on other sites

Nice. But how come I didn't see the function _ProcessExitCode in the help file !!?

Share this post


Link to post
Share on other sites

; Function Name: _ProcessExitCode()

That looks like the solution! I'll give it a try. Thanks!

Share this post


Link to post
Share on other sites

Nice. But how come I didn't see the function _ProcessExitCode in the help file !!?

As far as I can tell, AutoIt3Wrapper.au3 is not part of the standard distribution, so the UDFs inside AutoIt3Wrapper.au3 would not be in the help file.

[size="1"][font="Arial"].[u].[/u][/font][/size]

Share this post


Link to post
Share on other sites

I think the code shown tries to get too cute with the input parameter. Here's a more simplified version. This demo kicks off two ping processes, one succeeds and the second fails. It displays the PIDs, the process handles, and the exit codes for both:

$iRunPID1 = Run("ping.exe 127.0.0.1") ; Good ping
$iRunPID2 = Run("ping.exe 169.254.1.2") ; Bad ping
ConsoleWrite("$iRunPID1 = " & $iRunPID1 & ", $iRunPID2 = " & $iRunPID2 & @LF)
$hRun1 = _ProcessGetHandle($iRunPID1)
$hRun2 = _ProcessGetHandle($iRunPID2)
ConsoleWrite("$hRun1 = " & $hRun1 & ", $hRun2 = " & $hRun2 & @LF)

; Wait for both to finish...
ProcessWaitClose($iRunPID1)
ProcessWaitClose($iRunPID2)

$iExit1 = _ProcessGetExitCode($hRun1)
$iExit2 = _ProcessGetExitCode($hRun2)
_ProcessCloseHandle($hRun1)
_ProcessCloseHandle($hRun2)
ConsoleWrite("$iExit1 = " & $iExit1 & ", $iExit2 = " & $iExit2 & @LF)

; Return handle of given PID
Func _ProcessGetHandle($iPID)
    Local Const $PROCESS_QUERY_INFORMATION = 0x0400
    Local $avRET = DllCall("kernel32.dll", "ptr", "OpenProcess", "int", $PROCESS_QUERY_INFORMATION, "int", 0, "int", $iPID)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return $avRET[0]
    EndIf
EndFunc   ;==>_ProcessGetHandle

; Close process handle
Func _ProcessCloseHandle($hProc)
    Local $avRET = DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hProc)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return 1
    EndIf
EndFunc   ;==>_ProcessCloseHandle

; Get process exit code from handle
Func _ProcessGetExitCode($hProc)
    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   ;==>_ProcessGetExitCode

>_<


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

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