StandardOutput ReadToEnd when process pauses by default - c#

I must have looked through hundreds of articles related to the StandardOutput ReadtoEnd halting but none of them seem to answer my specific question.
The scenario I have is that I'm creating a wrapper for a 3rd party console app to be used in my ASP.NET MVC application. I start the process, pass it an input string (which is a dot file in string format) and the app returns a file (pdf in this case).
The file is placed into the stdout (according to the docs) however I don't seem to be able to read the data out.
When I run the console app manually, I receive the file as text in the output window but the program never really "exits". I have to CTRL+C to end the process.
I'm guessing this is why my calls to
process.StandardOutput.ReadToEnd();
Just hang?
Can anyone shed a bit of light into what I'm doing wrong. I'd like to return the file that's received in the output as a byte[] from my method call.
Thanks and appologies if it seems like this is a duplicate.

There are two problems:
ReadToEnd() returns a string. That's no good idea, if the data is binary
ReadToEnd() doesn't return, because the program never exits
Because of this, try reading the underlying stream (process.StandardOutput.BaseStream) with the more low level stream methods like Stream.Read and detect yourself when the program finished sending its data.

Related

How to parse a third party console application showing the status of external process (C#)?

The following video (gif) shows a third party console application that is managing an external process.
I'm looking to parse the information in the standard output to show it in a WinForm (C#).
I tried various approaches (for example here) but none seems to work, meaning nothing in the StreamReader, neither OutputDataReceived event.
If the text have new line characters, there is not issue. But is not the case with this app.
Any advice is appreciated.
Thanks
It may depend on the operating system. But it looks like the line gets rewritten. In this case you would need to read the stream buffer before it gets "committed" by a newline. (As you found out. IISC, the answer you linked uses BeginOutputReadLine.)
So, when you have your stream (e.g. standard input?) You might be able to read the buffer more precisely.
Hope, I got the question right :)

Problem with ivi.visa reading binary block data

I am writing an application which communicates with a network analyser using ivi.visa from Keysight. I often work remotely where I don't have an instrument, so I decided to write an application that can respond to the SCPI commands I need. This works ok for things like "*IDN?", but when I try to receive a binary block using ReadBinaryBlockOfByte(), the call terminates when it sees a newline character in the data.
If I set TerminationCharacterEnabled to false, all reads timeout. This is mentioned in the Keysight visa.net examples, so it doesn't seem to be an option.
So how can I read binary data?

In my C# code does the computer wait until output is complete before moving on?

Let's say I make a long string called 'lotsofdata', and then output its content with this code:
string outputFilePath = #"C:\output.txt";
System.IO.File.WriteAllText(outputFilePath, lotsofdata);
SpecialFunction1();
SpecialFunction2();
SpecialFunction3();
My question is, does the computer completely finish writing all of the stuff to output.txt before moving on to running SpecialFunction1? Or, does it set the outputting process in motion and move on to SpecialFunction1 before the outputting process is complete?
I'm asking because I want to make sure output.txt is done being written to before proceeding to SpecialFunction1() and I don't know how to ensure this.
Simple answer is yes.
The underlying stream is filled and closed (the important bit) before the WriteAllText method exits.
File.WriteAllText Method
Creates a new file, write the contents to the file, and then closes
the file. If the target file already exists, it is overwritten.
http://msdn.microsoft.com/en-us/library/system.io.file.writealltext%28v=vs.110%29.aspx
This is not a golden rule for all file writing. If you were writing directly to a FileStream, you would need to make sure you call Flush or Close (ideally, you should always call Close anyway) if you want to make sure that the file is actually written before continuing.
FileStream.Close Method
Any data previously written to the buffer is copied to the file before
the file stream is closed, so it is not necessary to call Flush before
invoking Close. Following a call to Close, any operations on the file
stream might raise exceptions. After Close has been called once, it
does nothing if called again.
http://msdn.microsoft.com/en-us/library/aa328800%28v=vs.71%29.aspx
The key takeaway for you here is that any operation that flushes a stream will not exit until the data has been written to its destination.
Yes, in the code provided first you will finish with the writing text to the file, and only after will run other SpecialFunction functions.
According to the File.WriteAllText documentation:
The file handle is guaranteed to be closed by this method, even if
exceptions are raised
So you should not have any concurent IO issues even on big files.
System.IO.File.WriteAllText when completes, will flush all the text to the filesystem cache, then, it will be lazily written to the drive.
All happening in the same thread, therefore your file will be written before anything else happens.

How can I obtain console application output when running it as a process in a C# DLL file?

I am working on method in a DLL. In my method I have been writing to the event log to allow me to determine whether things are working as I expect. One of the tasks I do in the method is create a process and run a command line application and I want to be able to capture the output of this that is normally written to the console and write it to the eventlog.
Code:
Process getNextIons = new Process();
getNextIons.StartInfo.FileName = #"""C:\Program Files\OpenMS-1.6\PrecursorIonSelector.exe""";
getNextIons.StartInfo.Arguments = #"-ini ""C:\Program Files\OpenMS-1.6\precursorionselector.ini""";
getNextIons.StartInfo.UseShellExecute = false;
getNextIons.StartInfo.RedirectStandardOutput = true;
getNextIons.Start();
getNextIons.WaitForExit();
System.Diagnostics.EventLog.WriteEntry("FMANWiff", "IPS: " + getNextIons.StandardOutput.ReadToEnd());
I have a console test application that calls my method and when I do this I am able to see that the process was started and ran correctly, however when I actually try to make use of the DLL, not using the test application, all I end up seeing is an entry:
IPS: And none of the output. I can tell it is running, however, as I can see a number of output files being updated.
Why am I not getting any output and how I can rectify this?
According to the Process.StandardOutput documentation your code has a potential deadlock.
When the caller reads from the redirected stream of a child process, it is dependent on the child. The caller waits on the read operation until the child writes to the stream or closes the stream. When the child process writes enough data to fill its redirected stream, it is dependent on the parent. The child process waits on the next write operation until the parent reads from the full stream or closes the stream. The deadlock condition results when the caller and child process wait on each other to complete an operation, and neither can proceed.
To avoid the possible deadlock, the last two lines of your sample code should be switched. You should also consider redirecting StandardError.
In your library, instead of writing directly to the location of choice you should be using
System.Diagnostics.Trace. By using Trace you can have your outside console application or whatever it be subscribe to the Trace event using a TraceListener.
By using Trace and TraceListeners, you can make you application adaptable to whatever logging situation you require without having to modify your library every time you want to change the logging system.
Below is a link to another Stack Overflow thread about trace logging with some good examples and information.
How can I add (simple) tracing in C#?

Does STDIN/STDOUT flush data all at once or character by character?

I'm using C# to read another program's STDOUT. If I do this:
StreamReader reader = process.StandardOutput;
reader.ReadToEnd();
Is it guaranteed to get the last thing flushed out to the program's STDOUT in its entirety? Or is kind of like TCP where I'd have to have a message terminator or length header?
by default StandardOutput is buffered, which means that you would likely get whole messages from the other end (or multiple whole messages). But its not really guaranteed, especially because process you are reading from could have changed the buffering of StandardOutput.
A message terminator would be the best way to figure it out. though usually with processes communicating over StandardOutput everything is line based so simply using newlines as message terminators is probably the simplest and most common place to start.
reader.ReadToEnd() doesn't return until the process terminates, so after that call you should see everything that it wrote to stdout. Buffering would only affect how quickly it gets from the other program into your reader's buffer, but your code can't tell the difference (at least on this thread) because it's still waiting for ReadToEnd() to return.

Categories

Resources