MHz Posted March 14, 2006 Share Posted March 14, 2006 (edited) Summary With the new StdoutRead/StderrRead etc. when using the Run() function. It is not currently a builtin feature for AutoIt3 to return the exitcode from Run(). I have just seen a request for the feature so thought best to post here to save reposting in support. This UDF will return exitcodes to users of the success with exitcode. So as a general benefit to the AutoIt users. Thanks must be awarded to DaveF for posting the DllCalls to my awareness some time ago, so I just needed to package them into UDFs for general use. Tested with AutoIt 3.3.8.1 . Simple view of usage You need to call the function _ProcessOpenHandle() immediately after the use of Run() to get the process handle. Then you call the function _ProcessGetExitCode() when the process has exited so as to retrieve the exitcode. Use _ProcessCloseHandle() to close the handle that was returned from _ProcessOpenHandle() to cleanup. Functions included _ProcessOpenHandle() _ProcessGetExitCode() _ProcessCloseHandle() Download exitcode-from-run.zip The zip file contains ProcessGetExitcode.au3 and the examples. Default example Use all 3 functions from ProcessGetExitcode.au3 #include 'ProcessGetExitcode.au3' Global $data, $exitcode, $handle_pid, $pid ; run the process with stdout flag STDERR_MERGED $pid = Run('"' & @ComSpec & '" /c echo Hello world && Exit 13', '', Default, 8) ; open process handle $handle_pid = _ProcessOpenHandle($pid) ; get stdout data Do Sleep(10) $data &= StdOutRead($pid) Until @error ; require process to be closed before calling _ProcessGetExitCode() ProcessWaitClose($pid) ; get exitcode of process $exitcode = _ProcessGetExitCode($handle_pid) ; close process handle _ProcessCloseHandle($handle_pid) MsgBox(0x40000, @ScriptName, _ '$exitcode: ' & $exitcode & @CRLF & _ '$data: ' & $data _ ) WinAPI* example Only uses _ProcessGetExitCode() from ProcessGetExitcode.au3 #include 'ProcessGetExitcode.au3' #include <WinAPI.au3> Global Const $PROCESS_QUERY_INFORMATION = 0x400 Global $data, $exitcode, $handle_pid, $pid ; run the process with stdout flag STDERR_MERGED $pid = Run('"' & @ComSpec & '" /c echo Hello world && Exit 13', '', Default, 8) ; open process handle $handle_pid = _WinAPI_OpenProcess($PROCESS_QUERY_INFORMATION, 0, $pid) ; get stdout data Do Sleep(10) $data &= StdOutRead($pid) Until @error ; require process to be closed before calling _ProcessGetExitCode() ProcessWaitClose($pid) ; get exitcode of process $exitcode = _ProcessGetExitCode($handle_pid) ; close process handle _WinAPI_CloseHandle($handle_pid) MsgBox(0x40000, @ScriptName, _ '$exitcode: ' & $exitcode & @CRLF & _ '$data: ' & $data _ ) Updated UDFs to be compatible with WinAPI* UDFs. 3 UDFs now instead of 2. MSDN mentions WinXP and above for GetExitcodeProcess so if it is untrue then confirm with a reply. Thanks to psychotik2k3 for emailing me to fix the corrupted code. My apologies to anyone who suffered from this issue. Cheers Edited June 21, 2013 by MHz Link to comment Share on other sites More sharing options...
nfwu Posted March 14, 2006 Share Posted March 14, 2006 Very Useful... #) TwitterOut of date stuff:Scripts: Sudoku Solver | Webserver | 3D library (Pure AutoIt) | Wood's GadgetsUDFs: _WoodUniqueID() | _DialogEditIni() | _Console*() | _GetIPConfigData() | _URLEncode/Decode() Link to comment Share on other sites More sharing options...
jpm Posted March 14, 2006 Share Posted March 14, 2006 Summary: With the new StdoutRead/StderrRead etc. when using the Run() function. It is not currently a builtin feature for AutoIt3 to return the exitcide from Run(). I have just seen a request for the feature so thought best to post here to save reposting in support. This UDF is now implemeted in CompileAu3, to return exitcodes to users of the success of scripts, Au3Check etc. So as a general benefit to the AutoIt community, I would like to share this UDF in open view. Many Thanks must be awarded to DaveF for posting the DllCalls to my awareness some time ago, so I just needed to package them into a UDF for general use. Simple view of usage: You need to call the function straight after the use of Run to get the process handle (only use 1 parameter), then you call the function a 2nd time when the process has exited, to retrieve the exitcode (need 2 parameters). $pid = Run('file.exe') $handle = _ProcessExitCode($pid) While ProcessExists($pid) Sleep(10) WEnd $exitcode = _ProcessExitCode($pid, $handle) Exit $exitcode UDF with a working test of operation: expandcollapse popup#region - Test ; test file using Exit 3 Do $path = Random(1000, 2000, 1) & '.au3' Until Not FileExists($path) If Not FileExists($path) Then FileWrite($path, 'Exit ' & Random(0, 19, 1)) $read = FileReadLine($path) $pid = Run(@AutoItExe & ' "' & $path & '"') $handle = _ProcessExitCode($pid) While ProcessExists($pid) Sleep(10) WEnd $exitcode = _ProcessExitCode($pid, $handle) FileDelete($path) MsgBox(0x0, 'Returns codes of ' & $path, _ 'Line: ' & @TAB & $read & @LF & @LF & _ 'PID: ' & @TAB & $pid & @LF & @LF & _ 'Exitcode: ' & $exitcode) Exit $exitcode EndIf #endregion ;=============================================================================== ; ; 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_ptr', $v_Placeholder) If Not @error Then Return $h_Process[2] EndIf Return 0 EndFunc Cheers This UDF is producing a memory leak as no CloseHandle of the process handle is done. after retrieving the exitcode. Perhaps it would be clearer to have a _ProcessOpenHandle, _ProcessGetExitCode and _ProcessCloseHandle if we really want to retrieve more than once the exitcode. Link to comment Share on other sites More sharing options...
MHz Posted March 14, 2006 Author Share Posted March 14, 2006 (edited) This UDF is producing a memory leak as no CloseHandle of the process handle is done. after retrieving the exitcode. Perhaps it would be clearer to have a _ProcessOpenHandle, _ProcessGetExitCode and _ProcessCloseHandle if we really want to retrieve more than once the exitcode. Ok, I need to do what you recommend. 3 Functions would now make a handful to use now as use of 3 function calls to accomplish the task. I'm not sure why you want to get the exitcode more then once when you store it in a variable? How about this concept of usage, JPM? Is the leak fixed with this? expandcollapse popup#region - Test ; test file using an Exit code Do $path = Random(1000, 2000, 1) & '.au3' Until Not FileExists($path) If Not FileExists($path) Then FileWrite($path, 'Exit ' & Random(0, 19, 1)) $read = FileReadLine($path) $pid = Run(@AutoItExe & ' "' & $path & '"') $handle = _ProcessOpenHandle($pid) While ProcessExists($pid) Sleep(10) WEnd $exitcode = _ProcessGetExitCode($handle) _ProcessCloseHandle($handle) FileDelete($path) MsgBox(0x0, 'Returns codes of ' & $path, _ 'Line: ' & @TAB & $read & @LF & @LF & _ 'PID: ' & @TAB & $pid & @LF & @LF & _ 'Exitcode: ' & $exitcode) Exit $exitcode EndIf #endregion 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 0 EndFunc Func _ProcessGetExitCode($h_Process) ; Return Process Exitcode of PID Local $v_Placeholder If IsArray($h_Process) Then $h_Process = DllCall('kernel32.dll', _ 'ptr', 'GetExitCodeProcess', _ 'ptr', $h_Process[0], _ 'int_ptr', $v_Placeholder) If Not @error Then Return $h_Process[2] EndIf Return 0 EndFunc 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 Edit: I'm not getting a positive return on the CloseHandle. Working on it. Edit: Working without error now. Was just a typo causing grief. Edited March 14, 2006 by MHz Link to comment Share on other sites More sharing options...
Moderators SmOke_N Posted March 14, 2006 Moderators Share Posted March 14, 2006 Edit: I'm not getting a positive return on the CloseHandle. Working on it. Anything you'd like us to try... maybe to help you out a bit? Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer. Link to comment Share on other sites More sharing options...
MHz Posted March 14, 2006 Author Share Posted March 14, 2006 See my 2nd edit, thanks. I made a typo in the name of the dll. The last post of code is my working proposal for use currently. Unless something else needs attention that someone spots. Link to comment Share on other sites More sharing options...
jpm Posted March 14, 2006 Share Posted March 14, 2006 @MHz If you don't want 3 functions you can add an optional parameter to _ProcessGetExitCode which will do the closing of the process handle or not. I will recommend the default being close not to forget. Link to comment Share on other sites More sharing options...
MHz Posted March 14, 2006 Author Share Posted March 14, 2006 (edited) @MHzIf you don't want 3 functions you can add an optional parameter to _ProcessGetExitCode which will do the closing of the process handle or not. I will recommend the default being close not to forget. Thanks JPM. Updated at 1st post. Please report any issues.Edit:Thanks for the positive comment, nfwu. Edited March 14, 2006 by MHz Link to comment Share on other sites More sharing options...
DaveF Posted March 14, 2006 Share Posted March 14, 2006 Woot! Way to go, MHz! Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines. Link to comment Share on other sites More sharing options...
MHz Posted March 14, 2006 Author Share Posted March 14, 2006 Thanks Dave. Your intial code helped to make a useful exitcode UDFs for Run(). I just packaged it up into some general UDFs that make it useful for any script. Thankfully, JPM noticed a missing step which is corrected. Your statement is positive that it is deemed good code. Link to comment Share on other sites More sharing options...
Valik Posted March 14, 2006 Share Posted March 14, 2006 You don't mention that GetExitCodeProcess() can return STILL_ACTIVE if called on a running process. Link to comment Share on other sites More sharing options...
MHz Posted March 14, 2006 Author Share Posted March 14, 2006 (edited) You don't mention that GetExitCodeProcess() can return STILL_ACTIVE if called on a running process.Your right, Valik. May just need to check to see if the Pid is still active, set error and then close the handle to resolve the event. I updated the 1st post to reflect the changes of this. Thanks for the alert. Edited March 14, 2006 by MHz Link to comment Share on other sites More sharing options...
rehnmark Posted February 9, 2007 Share Posted February 9, 2007 Thanx!!!, works perfect! Link to comment Share on other sites More sharing options...
MHz Posted February 9, 2007 Author Share Posted February 9, 2007 Thanks, I go the JPM idea of 3 funcs rather then the consolidated just simply for that view as those funcs are multipurpose for other functions. Link to comment Share on other sites More sharing options...
Gigglestick Posted July 30, 2008 Share Posted July 30, 2008 (edited) This is great! I'd love to see _ProcessOpenHandle, _ProcessCloseHandle, and _ProcessGetExitCode added to Process.au3, as well as maybe the following change to _RunDOS: Current _RunDOS: (Returns only the exit code, output must be obtained by piping the output to a temporary file) Func _RunDOS($sCommand) Local $nResult = RunWait(@ComSpec & " /C " & $sCommand, "", @SW_HIDE) Return SetError(@error, @extended, $nResult) EndFunc;==>_RunDOS Proposed _RunDOS: (Captures and returns the STDIO, and @error=exit code) Func _RunDOS($sCommand) Local $iPID = Run(@ComSpec & " /C " & $sCommand, "", @SW_HIDE, 8); 8 = StdOut + StdErr merged ProcessWaitClose($iPID); Wait for the process to finish, like RunWait would Return SetError(_ProcessGetExitCode($iPID, _ProcessOpenHandle($iPID)), 0, StdoutRead($iPID)) EndFunc ;==>_RunDOS Returns the STDIO of the process, and @error is the exitcode, so this would be a code-breaking, but worth it instead of piping output to a file as I'm sure many people currently do it. Alternative, non-code-breaking: Func _RunDOS($sCommand, $iMode=0) ; $iMode - 0 = Classic (return exit code in @error) ; 1 = Return the STDIO, @error = exit code If $iMode = 0 Then Local $iResult = RunWait(@ComSpec & " /C " & $sCommand, "", @SW_HIDE) Return SetError(@error, @extended, $iResult) Else Local $iPID = Run(@ComSpec & " /C " & $sCommand, "", @SW_HIDE, 8); 8 = StdOut + StdErr merged ProcessWaitClose($iPID); Wait for the process to finish, like RunWait would Return SetError(_ProcessGetExitCode($iPID, _ProcessOpenHandle($iPID)), 0, StdoutRead($iPID)) EndIf EndFunc ;==>_RunDOS Edited July 30, 2008 by c0deWorm My UDFs: ExitCodes Link to comment Share on other sites More sharing options...
Allow2010 Posted August 13, 2011 Share Posted August 13, 2011 the codebox in the first post seems to be brolen, only shows a few lines of code and some garbage characters... can anyone post the latest version of this udf or tell me where i csn find it...thanks ! Link to comment Share on other sites More sharing options...
monoscout999 Posted August 13, 2011 Share Posted August 13, 2011 the codebox in the first post seems to be brolen, only shows a few lines of code and some garbage characters...can anyone post the latest version of this udf or tell me where i csn find it...thanks !I never knew why old threads have that.. but look the dates of the posts, this have been abandoned since 2008 Link to comment Share on other sites More sharing options...
MHz Posted June 21, 2013 Author Share Posted June 21, 2013 Corrupted code replaced with updated code. You can now use all 3 functions in the include file or just use _ProcessGetExitCode() with the Standard UDFs _WinAPI_OpenProcess() and _WinAPI_CloseHandle(). Thanks psychotik2k3 for the reminder. Link to comment Share on other sites More sharing options...
ypid-geberit Posted October 4, 2019 Share Posted October 4, 2019 @MHz Thanks very much for this UDF! To use this properly in projects, it needs to be clear under which software license you want this UDF to be used. Can you pick one maybe https://choosealicense.com Thank you again! Link to comment Share on other sites More sharing options...
Developers Jos Posted October 4, 2019 Developers Share Posted October 4, 2019 @ypid-geberit, Please don't do this for all the UDF's you are planning to use and use the approach as I have suppliedlied in the answer here: Jos SciTE4AutoIt3 Full installer Download page - Beta files Read before posting How to post scriptsource Forum etiquette Forum Rules Live for the present, Dream of the future, Learn from the past. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now