Sign in to follow this  
Followers 0
Gigglestick

Curious about a feature request rejection

9 posts in this topic

#1 ·  Posted (edited)

I submitted a request for a modification to the RunWait command, which was rejected, and I'm just curious about the response. I apologize if this is the incorrect forum or if I should have addressed this inside of trac.

The request was to give the RunWait command the ability to attach StdOut and StdErr so the output of the command could be captured exactly like it is with the Run command, using StdOutRead and StdErrRead.

Here is the response:

The way you do this is to use Run() with STDIO redirection. Then you use DllCall() with OpenProcess to open the process handle. You can then use ProcessWaitClose() to halt until the process exits. Finally you can use DllCall() and GetExitCodeProcesss to retrieve the exit code. And the StdXXXRead() functions will work, of course, since you have the PID.

So based on that response, I have to assume Run and RunWait were originally designed with two completely separate roles. RunWait was meant to run a command blindly with no ability to get a detailed response from the command other than the exitcode, while Run was designed with the ability to capture more detail, in fact, everything but the exitcode.

This post is not meant to be an attack or challenge. I'm really just curious why this functionality wasn't implemented originally and why it was rejected. I understand the answer and and can write the code (possibly with a little help from the forums about the DllCall()'s), but to me this functionality makes sense to have built into AutoIt.

Does it not make sense to have the same functionality built into the RunWait command that the Run command has, such that you could use either command interchangeably, where the only difference is that one waits?

Edited by c0deWorm

My UDFs: ExitCodes

Share this post


Link to post
Share on other sites



When you run a process, you won't know when it finishes unless you actively monitor it. That is what RunWait does.

With Run, you have to monitor the end of the process yourself. The exit code can't be retrieved (with any useful value) before the process ends.

Share this post


Link to post
Share on other sites

When you run a process, you won't know when it finishes unless you actively monitor it. That is what RunWait does.

With Run, you have to monitor the end of the process yourself. The exit code can't be retrieved (with any useful value) before the process ends.

Right. My request was addressing adding StdOut and StdErr to RunWait though, not exit code functionality in Run.

My UDFs: ExitCodes

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

You simply can't run any commands until RunWait() returns. Just use Run(), you may have to start a loop immediately after to check ProcessExsists().

$pid = Run("notepad.exe")
 
 Do
 Until NOT ProcessExists($pid)
 
 MsgBox(0,"","Exit code: " & _ProcessGetExitCode($pid,_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*', $v_Placeholder)
             If @error Then $i_Error = 1
         EndIf
     EndIf
  ; Close the process handle of a PID
     If $i_Error = 3 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

Function from here:

http://www.autoitscript.com/forum/index.php?showtopic=23096

Edited by weaponx

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

You simply can't run any commands until RunWait() returns. Just use Run(), you may have to start a loop immediately after to check ProcessExsists().

Thank you for the code snippet and the link.

I understand this, and I've used this many, many times (e.g. I have a script that starts several robocopy processes to expedite large data migrations, monitoring them in this way, and starting another one as one finishes, etc.).

I just don't understand why the StdOut/StdErr functionality of Run isn't built into RunWait. The code weaponx provided will suffice, but again, I'm just curious why two functions that would logically seem to provide nearly the same purpose can differ so much in functionality. Is it really that hard to add to RunWait? Or, rather, when StdOut/StdErr was added to Run, did nobody consider adding it to RunWait?

Thanks again for the example.

Edited by c0deWorm

My UDFs: ExitCodes

Share this post


Link to post
Share on other sites

Let me play the standard game of "turning the question around" with you:

Why would anything need to be added when you can easily accomplish it with a few scriptlines as shown in the helpfile?

:P


Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

Let me play the standard game of "turning the question around" with you:

Why would anything need to be added when you can easily accomplish it with a few scriptlines as shown in the helpfile?

:P

Umm... because it makes sense to have similar functionality in two functions that do the same thing?

Nevermind, I'll let it go. Apparently, I'm the only one who sees the value in it.


My UDFs: ExitCodes

Share this post


Link to post
Share on other sites

c0deworm, there are several reasons. First of all, as Jos has said (and me on the tracker), you can do it yourself with very little code. Second, STDIO stuff was added much later to Run(). STDIO was designed to take the PID. At the time it was originally written, you also had to actively read the data or your process would eventually dead-lock. RunWait() has never returned the PID and RunWait() obviously blocks. Since you could never read the buffer if you used RunWait(), and since you couldn't get the PID, either, it just made no sense to add it to RunWait(). Even if we were to solve the PID issue, chances are, you'd just dead-lock AutoIt and the child process anyway.

Now the STDIO stuff is written much better so that it won't dead-lock anything. However, that doesn't change the PID thing. Returning the PID via @extended is technically possible, but it's rather inconsistent.

There's really no incentive to add this. We know it's trivial to do, I've had a UDF that offers STDIO redirection, waiting and exit code functionality for years. And thanks to the rewrite of the STDIO stuff, the code is even easier than ever. The basic flow is (obvious pseudo-code):

Local $pid = Run(); Redirect STDIO
Local $hProcess = _WinAPI_OpenProcess($pid); Open with minimum rights needed to read the exit code.
ProcessWaitClose($pid)
Local $nExitCode = DllCall("GetProcessExitCode", "ptr", $hProcess)
_WinAPI_CloseHandle($hProcess)
Local $sStdOut = StdOutRead($pid); Reads all data.
Local $sStdErr = StdErrRead($pid); Reads all data.

; At this point, $nExitCode, $sStdOut and $sStdErr contains all the data the process was able to give us.

It takes very little effort to encapsulate that into a UDF which can either take some ByRef parameters for the two streams (and return the exit code) or just return an array with all the data.

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

@Valik:

Thank you for the explanation. That's all I was looking for, and I understand the thought process surrounding the issue now. You're right that my point was that it's a trivial thing to add, and I see your point also. That explanation would have been preferable in trac, but I know that's a real PITA to put that kind of detail in every request that comes in.

Next question: There's code posted to the forums to handle such a situation, and it appears to have been around for quite awhile (March 2006). Can we get that added to Process.au3 and the help file? Possibly with a mention and/or links to those functions on the Run page? A rewrite of _RunDOS seems appropriate, too, to provide all possible results (exitcode and STDIO) of a command, which maybe I'll take a shot at, and post appropriately.

Thanks again!

Edited by c0deWorm

My UDFs: ExitCodes

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