Sign in to follow this  
Followers 0
therks

Exit code + StdoutRead/StderrRead

4 posts in this topic

Is there any way to retrieve the exit code from a process while also being able to use StdoutRead/StderrRead?

Share this post


Link to post
Share on other sites



Have a look at this example that pulled from this and edited.

Example.au3

#include <Constants.au3>
#include "ProcessExitCode.au3"
 
$iPid = Run(@ComSpec & ' /c dir /g', @WindowsDir, @SW_SHOW, $STDERR_CHILD + $STDOUT_CHILD)
$hHandle = _ProcessGetHandle($iPid)
ShowStdOutErr($hHandle)
$iExitCode = _ProcessGetExitCode($iPid)
_ProcessCloseHandle($hHandle)
MsgBox(0, "Program returned with exit code:", $iExitCode)
 
$iPid = Run(@ComSpec & ' /c dir', @WindowsDir, @SW_SHOW, $STDERR_CHILD + $STDOUT_CHILD)
$hHandle = _ProcessGetHandle($iPid)
ShowStdOutErr($hHandle)
$iExitCode = _ProcessGetExitCode($hHandle)
_ProcessCloseHandle($hHandle)
MsgBox(0, "Program returned with exit code:", $iExitCode)
 
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

ProcessExitCode.au3

#include-once
; #FUNCTION# ====================================================================================================================
; Name...........: _ProcessGetHandle()
; Description ...: Returns a handle from use of Run().
; Syntax.........: _ProcessGetHandle($iPID)
; Parameters ....: $iPID - ProcessID returned from a Run() execution
; Return values .: On Success - Returns Process handle while Run() is executing (use above directly after Run() line with only PID parameter)
;                 On Failure - 0
; Author ........: MHz (Thanks to DaveF for posting these DllCalls in Support Forum)
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _ProcessGetHandle($iPID) ;Return handle of given PID
    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
 
; #FUNCTION# ====================================================================================================================
; Name...........: _ProcessCloseHandle()
; Description ...: Closes a handle from use of Run().
; Syntax.........: _ProcessCloseHandle($hProc)
; Parameters ....: $hProc - Process handle
; Return values .: On Success - Closes Process handle after a Run() has executed.;
;                 On Failure - 0
; Author ........: MHz (Thanks to DaveF for posting these DllCalls in Support Forum), PsaltyDS
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _ProcessCloseHandle($hProc) ;Close process handle
    Local $avRET = DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hProc)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return 1
    EndIf
EndFunc   ;==>_ProcessCloseHandle
 
; #FUNCTION# ====================================================================================================================
; Name...........: _ProcessGetExitCode()
; Description ...: Returns a handle/exitcode from use of Run().
; Syntax.........: _ProcessGetExitCode($hProc)
; Parameters ....: $hProc   - Process handle
; Return values .: On Success - Returns Process Exitcode when Process does not exist.
;                 On Failure - 0
; Author ........: MHz (Thanks to DaveF for posting these DllCalls in Support Forum), PsaltyDS
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
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   ;==>_ProcessGetExitCode

Adam

Share this post


Link to post
Share on other sites

Thanks, that works perfectly. And I can use _WinAPI_OpenProcess() and _WinAPI_CloseHandle() from the WinAPI.au3 include. Sorry for the horrendous reply time, I don't get back here often.

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

This a simpler quick and dirty way

FileDelete("C:\temp\errorlevel.txt")

$file = fileopen(@TempDir & "\CMD.bat",2)
FileWrite($file,"start /wait c:\temp\test2.exe" & @CRLF)
FileWrite($file,"echo %errorlevel% > C:\temp\errorlevel.txt" & @CRLF)
FileClose($file)

$PID = run(@TempDir & "\CMD.bat")


While ProcessExists($PID)
wend

$file = fileopen("C:\temp\errorlevel.txt",0)
msgbox(0,"",fileread($file))
fileclose($file)
Edited by castens

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

  • Similar Content

    • BlazerV60
      By BlazerV60
      Hello all,
      I've written the code below which launches chrome in incognito mode and then proceeds to go to the autoit website.
      From my understanding, the Run() command is also supposed to output the PID number related to the application that got launched from the Run command.
      However when I run the below lines, it outputs a PID number that is different from the newly launched chrome browser's PID number, does anyone know why and possibly explain how I could retrieve the accurate PID number associated with the newly launched browser?
      Global $iPid = Run(@ComSpec & ' /c start chrome.exe https://www.autoitscript.com/forum/ -incognito' ,"", "") msgbox(0,"",$iPid) Thank you,
      Brian
    • rootx
      By rootx
      I need help to understand why the run function does not work, but if i use it directly inside cmd shell the command works. $where is the name of the jpg file
      ShellExecute(@ComSpec ," /k C:\Users\root\Desktop\test\exiftool.exe -p $FileName "&'"'&$where&'"'&" > "&'"'&@ScriptDir&"\out.txt"&'"',@ScriptDir);<----- work Run("C:\Users\root\Desktop\test\exiftool.exe -p $FileName "&$where&" > "&@ScriptDir&"\out.txt",@ScriptDir);<--- doesn't work I would use the run command!
      Thx
    • nacerbaaziz
      By nacerbaaziz
      Hello
      How are you
      I have a question, please.
      I've created a window and i need
      when i run the script if it detect an other copy from the same script was runing
       the script close the first copy Automatically and run a new copy
      I want an example to understand it
    • OGA
      By OGA
      Hi, I'm new.
      Anyways, I'm using the RunBinary.au3 script by trancexx and I want to re-direct the STDOUT of the "child process" back to the autoit script that launches it. I'm attempting to do so using named pipes. If its possible to use StdoutRead instead of namedpipes please let me know. I'm just unsure of how to provide a handle of the childs STDOUT stream to that function. Though DllCall("kernel32.dll", "ptr", "GetStdHandle", "dword", "STD_OUTPUT_HANDLE") seems to get the handle?
      Please excuse any foolish mistakes because I'm new to STDOUT, runbinary and namedpipes. Here's the parts of the code I'm trying to use that are relevent:
      ;~~~Firstly I think I need to make a pipe that's inheritable.. which I may have done wrong Local $_SECURITY_ATTRIBUTES = DllStructCreate("dword Length;" & _ "int lpSecurityDescriptor;" & _ "bool InheritHandle;") ;***Not positive if bool works correctly here? DLLStructSetData($_SECURITY_ATTRIBUTES, "Length", DllStructGetSize($_SECURITY_ATTRIBUTES)) DLLStructSetData($_SECURITY_ATTRIBUTES, "lpSecurityDescriptor", 0) ;***This sets default state; "If the value of this member is NULL, the object is assigned the default security descriptor associated with the access token of the calling process." but I'm unsure if this is what I should use DLLStructSetData($_SECURITY_ATTRIBUTES, "InheritHandle", true);***True = Inheritable(but again I'm not positive the bool works correctly?) Global $hNamedPipe = _NamedPipes_CreateNamedPipe("\\.\pipe\poopp", _;Name 2, _;Direction: 2=both ;I only need 1 direction but I'm just using this for testing 1, _;Flags: 1=no extra instances of pipe are allowed to run 0, _;Security: No ACL Security 0, _;Type: 0=byte 0, _;ReadType: 0=byte 1, _;Wait: 0=Block(wait) 1=No block(no wait) 1, _;Max Instances of pipe allowed 4096, _;out size 4096, _;in size 9000, _;timeout DllStructGetPtr($_SECURITY_ATTRIBUTES));Default=0 which wouldn't make the handle inheritable ;~~~Next I would need to set the STARTUPINFO of the process ;code used by trancexx for the _STARTUPINFO Global $tSTARTUPINFO = DllStructCreate("dword cbSize;" & _ "ptr Reserved;" & _ "ptr Desktop;" & _ "ptr Title;" & _ "dword X;" & _ "dword Y;" & _ "dword XSize;" & _ "dword YSize;" & _ "dword XCountChars;" & _ "dword YCountChars;" & _ "dword FillAttribute;" & _ "dword Flags;" & _ "word ShowWindow;" & _ "word Reserved2;" & _ "ptr Reserved2;" & _ "ptr hStdInput;" & _ "ptr hStdOutput;" & _ "ptr hStdError") ;Attempting to set the values for namedpipe redirection DllStructSetData($tSTARTUPINFO, "Flags", 0x00000100) ;***Flag = STARTF_USESTDHANDLES (I think I set it correctly?) DllStructSetData($tSTARTUPINFO, "hStdOutput", $hNamedPipe) ;***Currently setting the output handle to the SERVER end of the NamePipe I'm creating (which I'm pretty sure is wrong but idk how to use the Client End) ;~~~code used by trancexx for CreateProcess Global $aCall = DllCall("kernel32.dll", "bool", "CreateProcessW", _ "wstr", $sExeModule, _ "wstr", $sCommandLine, _ "ptr", 0, _ "ptr", 0, _ "bool", true, _ ;***changed to inherit handles (not positive I did so correctly) was int 0 before "dword", 4, _ ; CREATE_SUSPENDED ; <- this is essential "ptr", 0, _ "ptr", 0, _ "ptr", DllStructGetPtr($tSTARTUPINFO), _ "ptr", DllStructGetPtr($tPROCESS_INFORMATION)) ;~~~~~Code used in a loop to try to see if anything is being written into the pipe If _IsPressed(35, $hDLL) Then Local $pipeData = _NamedPipes_PeekNamedPipe($hNamedPipe) If @Error Then MsgBox(1,"PipeData Error",@Error & " | " & $pipeData) Else Local $r = _ArrayDisplay($pipeData) If @Error Then MsgBox(1,"Array Error",@Error & " | " & $pipeData) EndIf EndIf  
      I'm not using this exact code cause I changed it around some for the post. I'm mainly wondering how to correctly use the client end of the name pipe? I also had some values I wasn't sure if I set correctly because I don't have experience with com objects. And It seems the process launched needs to be the child?.. Can the process started through the autoitscript can be considered the child process and the script the parent process?
       
      Guides I'm using for this:
      https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
      https://support.microsoft.com/en-us/help/190351/how-to-spawn-console-processes-with-redirected-standard-handles
    • kawliga751
      By kawliga751
      I am attempting to run an Autoit.exe with schtasks every weekday @ 9:05 am.
      I have the below
      C:\>SchTasks /Create /TN "P10Run" /TR "O:\AUTOIT\P40 Run.au3" /SC WEEKLY /D MON, TUE,WED,THU,FRI /ST 09:05:00 SUCCESS: The scheduled task "P10Run" has successfully been created. I also did a "test" run :
      C:\>Schtasks /Run /TN "P10Run SUCCESS: Attempted to run the scheduled task "P10Run". But when I run my query to verify success my "Last Result" seems to indicate that the script did not run:
      C:\>SCHTASKS /QUERY /FO LIST /V /TN "P10RUN" Folder: \ HostName: xxxxxxxxxxxxxxxx TaskName: \P10RUN Next Run Time: N/A Status: Could not start Logon Mode: Interactive only Last Run Time: 6/14/2017 9:08:56 AM Last Result: -2147024894 Author: xxxxxxx Task To Run: O:\AUTOIT\P40 Run.au3 Start In: N/A Comment: N/A Scheduled Task State: Enabled Idle Time: Disabled Power Management: Stop On Battery Mode, No Start On Batterie s Run As User: xxxxxxxxx\xxxxxxxx Delete Task If Not Rescheduled: Enabled Stop Task If Runs X Hours and X Mins: 72:00:00 Schedule: Scheduling data is not available in this f ormat. Schedule Type: Weekly Start Time: 9:05:00 AM Start Date: 6/14/2017 End Date: N/A Days: MON, TUE, WED, THU, FRI Months: Every 1 week(s) Repeat: Every: Disabled Repeat: Until: Time: Disabled Repeat: Until: Duration: Disabled Repeat: Stop If Still Running: Disabled C:\> Is there something missing in my command? Also is there a better way to make sure that the script does in fact sun successfully?
      Thanks In Advance!