External command-line process never returns

955 Views Asked by At

I'm using the following vb.net code to run an external command line application and read back its output:

Public Shared Function Execute(ByVal command As String, ByVal params As String, ByVal workingdir As String) As String
    psi = New ProcessStartInfo(command)
    psi.WorkingDirectory = workingdir
    psi.RedirectStandardOutput = True
    psi.WindowStyle = ProcessWindowStyle.Hidden
    psi.UseShellExecute = False
    psi.CreateNoWindow = True
    psi.Arguments = params
    proc = Process.Start(psi)
    Dim myOutput = proc.StandardOutput
    proc.WaitForExit() 'Problem is here!!!!!!
    Dim ret = myOutput.ReadToEnd
    Return ret
End Function

This code has worked perfectly for several applications... until now. The problem is this: I'm now using it to run "aapt.exe" (a tool that gives you info on android apk applications) on a bunch o files, and the code gets stuck (never returns) in the point I commented but only on 3 particular files out of a total of 81

Of course my first thought was that the external program was failing/getting stuck on those particular files, but I tested the same command manually from a command prompt and it works perfectly! Furthermore: i added a timeout to the code, like this:

    proc.WaitForExit(10000)

And in this case the process returns (obviously) but what is interesting is that the output is correct and complete! This implies that the external program is running correctly until the end, so why doesn't the process return on its own?? Is there any feasible way to debug this?

Thanks

EDIT: After hours of testing, I came to the conclusion that the problem lies in the "RedirectStandardOutput" option. No matter which order I execute/read it it hangs on some executions. I didn't find a proper solution to this, I implemented a (horrible) workaround where I disable stdout redirection and instead output the stdout to a file, then immediately re-read it in my code when the process terminates (it does terminate properly this way at least). Not an elegant solution, and I'd still like to get to the bottom of this, so I'm leaving the question open if anyone has better ideas than mine.

2

There are 2 best solutions below

1
On

I think you probably just need to call Dim ret = myOutput.ReadToEnd before proc.WaitForExit(). MSDN warns about a deadlock from calling WaitForExit() first: "A deadlock condition can result if the parent process calls p.WaitForExit before p.StandardOutput.ReadToEnd and the child process writes enough text to fill the redirected stream. The parent process would wait indefinitely for the child process to exit. The child process would wait indefinitely for the parent to read from the full StandardOutput stream." So I'm guessing those 3/81 files just have more output than the others.

0
On

Have you tried adding /C parameter to the end so it will return after exiting. e.g. cmd /C " "abc.exe" "

Here "/C" is important it tells command prompt to exit after it is done.