I have some code that spawns a process, the file being executed is a Java application and my intent is to read the output from it.
The problem is that when I call Start, I am unable to read the output stream after that point. If I test and call Console.Beep after calling Start then the beep will occur - so it is obviously executing these lines.
Control.CheckForIllegalCrossThreadCalls = false;
Process java = new Process();
java.StartInfo.FileName = "java";
java.StartInfo.Arguments = "-Xms1024M -Xmx1024M -jar craftbukkit-0.0.1-SNAPSHOT.jar nogui";
java.StartInfo.RedirectStandardOutput = true;
java.StartInfo.UseShellExecute = false;
java.Start();
System.Console.Beep();
System.Console.Write("hejsan");
StreamReader Reader = java.StandardOutput;
txtLog.Text = Convert.ToString(System.Console.Read());
broadcast(Convert.ToString(System.Console.Read()), "[Server]", false);
Why can't I read from the output stream?
Take a look at this Microsoft reference of StandardOutput.
Basically, you need to call WaitForExit and attempt to read the stream after that. It's a blocking call, so unless you do some funky stuff with it and asynchronism, this is fairly straight forward:
if (java.Start())
{
java.WaitForExit();
var reader = java.StandardOutput;
output = reader.ReadToEnd();
}
It's worth mentioning here that the Start method returns a boolean value indicating whether or not the process was actually started - this helps us decide what to do, and whether or not we can do it.
On another note, I can't help but notice that you don't actually try to read from the output stream, you simply declare a variable with a reference to it; in order to utilise it, then you will need to call the methods exposed by the class, such as ReadToEnd - I have added usage to the example above.
Related
I am trying to inherit a Pipe Handle from a C# parent process to a C++ Child process.
I create the Parent in the C# Process in the following way:
AnonymousPipeServerStream pipe = AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
string pipeName = pipe.GetClientHandleAsString();
I then pass the handle to the Client Process like this:
ProcessStartInfo clientProcessStartInfo = new ProcessStartInfo("cpp_process.exe", pipeName);
startInfo.UseShellExecute = false;
Process process = new Process {
StartInfo = startInfo
}
process.Start();
pipe.DisposeLocalCopyOfClientHandle();
In the Child C++ Process, i get the Pipe Handle like this:
std::string pipeHandleString = argv[1];
int pipeHandleInt = std::stoi(pipeHandleString);
HANDLE pipeHandle = (void*) pipeHandleInt;
But when i try to use the Pipe Handle in the Child Process like this:
std::array<char, 256> buffer = {};
DWORD numberOfBytesRead;
BOOL result = ReadFile(pipeHandle, &buffer, 256, &numberOfBytesRead, nullptr);
Result is FALSE and GetLastError() returns This handle is invalid.
As far as i understand it, the Child Process should inherit the pipe handle automatically?
Removing pipe.DisposeLocalCopyOfClientHandle() does not change the Result.
Also, using the pipe handle in a C# Client Process like this:
AnonymousPipeClientStream pipe = new AnonymousPipeClientStream(PipeDirection.In, args[1]);
Works just fine, so im guessing the C# implementation does something to the Handle that i'm missing in my C++ implementation, but i cant figure out what that is.
The above code works as expected, the problem was outside of the minimum viable example i put together.
I had the pipe handling wrapped in a class.
Said class had a destructor that closed the pipe handle.
This destructor was running too often, even before the first read from the pipe leading to the invalid handle error.
Commenting out the call to CloseHandle / Preventing the Destrutor from being run when it shouldn't fixed the error.
I am writing an application to manage processes and handle failovers. This program is written in C# for .NET Core and will run on Ubuntu Server 16.04 x64.
I have this code to create processes and track them, with exit events and such
ProcessStartInfo psi = new ProcessStartInfo
{
WorkingDirectory = "/home/xyzserver/someprocess",
FileName = "mono",
Arguments = "someprocess.exe",
RedirectStandardOutput = true
};
_proc = Process.Start(psi);
_proc.EnableRaisingEvents = true;
_proc.Exited += ProcOnExited;
I understand from the docs here that calls to Console.WriteLine will block if the _proc.StandardOutput stream is full. I want to prevent this behavior and dispose all the output from the managed application, since it will also write to a physical log on its own.
In addition, I would like to avoid storing any of the output in any unused stream buffers since they will never be used. A preferred solution will not UseShellExecute.
I have considered adding these 2 lines in the hope that any received data will be disposed, but am unsure about correctness.
_proc.OutputDataReceived += (sender, eventArgs) => {};
_proc.BeginOutputReadLine();
Is there a better way to accomplish this? Thoughts or comments are appreciated.
I manually ran the test on .NET Core using 3 programs:
An HTTP server to track the TextOutputter program.
A TextOutputter program that prints 1000 characters and makes an HTTP request every second.
a ProgramRunner that runs one instance of TextOutputter.
Without the 2 lines, the buffer fills upto 64k and stalls. With the 2 lines, there is no stalling.
Im using Stockfish game engine to power Human Vs Computer games.
Here is first part of the code:
Process _proc= new Process();
_proc.StartInfo = new ProcessStartInfo(path);
_proc.StartInfo.RedirectStandardInput = true;
_proc.StartInfo.RedirectStandardOutput = true;
_proc.StartInfo.UseShellExecute = false;
_proc.StartInfo.CreateNoWindow = true;
_proc.Start();
_proc.StandardInput.WriteLine("uci");
_proc.StandardInput.WriteLine("ucinewgame");
At this point everything is ok, but when I try to read StandardOutput something weird happens.
string result = _proc.StandardOutput.ReadToEnd();
Stockfish.exe program pops-up my application is running but code after that line is not executing. When I press pause, it points at this line:
If I use:
while (!_proc.StandardOutput.EndOfStream)
{
result += _proc.StandardOutput.ReadLine();
}
Same thing happens only at while statement. result has its full value there, all the text is written into it.
Is there any way to overcome this without async reading?
Side problem:
Since this is all part of singleton class that is used over whole ASP.NET application, i dont feel like using async reading since Im not sure how can I protect (with locking) multiple threads writing into it. Also, I dont know how to stop current thread since the processing of command can last up to 10 sec.
I don't feel like using Thread.Sleep() to constantly check for end of reading output, not elegant.
Considering side problem, how could i avoid multithread problems if async is only solution?
My threading knowledge is weak, so please have that in mind when giving thread related answers. Thank you.
The call to StandardOutput.ReadToEnd will block until this process ends. Is the goal here to read, process, and respond to various text commands from the process you spawn as you receive them?
You must approach this via asynchronous reading.
For example, you could setup a listener to Process.OutputDataReceived. Then call Process.BeginOutputReadLine to start reading. Your code will continue execution. Meanwhile, the .NET Framework will handle incoming text messages on a separate thread.
I got following code
System.Diagnostics.Process capp = new System.Diagnostics.Process();
capp.StartInfo.UseShellExecute = false;
capp.StartInfo.RedirectStandardOutput = true;
capp.StartInfo.RedirectStandardError = true;
capp.EnableRaisingEvents = false;
capp.StartInfo.FileName = "app.exe";
capp.StartInfo.Arguments = "-i -v -mj";
capp.Start();
consoleOutput = capp.StandardOutput.ReadToEnd() + capp.StandardError.ReadToEnd();
if (!capp.WaitForExit(10000)) capp.Kill();
and problem, if outside application works correctly it takes less than 10 seconds for it to complete its tasks. If it stop/hung for some reason despite of using
if (!capp.WaitForExit(10000)) capp.Kill();
as suggested in some other topic, it keeps working. Above line seem not to work at all in my case, i guess it has to do with fact i read StandardOutput and StandardError. How to fix my code to make reading output and WaitForExit() to work aside?
If you don't always read from both StandardOutput and StandardError the buffers can fill causing the process to block.
You first try to read StandardOutput to the end. The process you run might be writing a lot of data to StandardError until it blocks and can't write more. Then this results in your application blocking as it doesn't even start reading from StandardError until the process closes its StandardOutput. This creates a deadlock and neither process will continue.
I suggest you use the solution I've posted here. It uses asynchronous reads to read from both StandardOutput and StandardError, avoiding deadlocks.
I'm trying to put together a wrapper around a console application using StandardInput and StandardOutput. I'm getting stuck where the console application would prompt for input such as a password.
I'd like to read from StandardOutput, prompt the user using the read text, and write the user's input back to the console application using its StandardInput. Seems easy enough, here's what I have currently:
Process process = new Process()
{
StartInfo =
{
FileName = "bin\\vpnc.exe",
Arguments = "--no-detach --debug 0",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
}
};
process.OutputDataReceived += (s, args) =>
{
textBlock1.Dispatcher.Invoke(new Action(() =>
{
textBlock1.Text += args.Data;
}));
};
process.Start();
process.BeginOutputReadLine();
The problem is that BeginOutputReadLine() is doing just that...waiting for a line ending. In this case it just sits, and sits, and sits because there is no line to read...the console application has written out text with no line ending and is waiting for input. Coincidentally, when I manually kill the process the event fires and I get the text.
Is there a way to tell that the process is waiting for StandardInput? Or am I missing a completely obvious way to accomplish the goal?
Unless you need something asynchronous you probably want ReadToEnd.
Here is a list of all StreamReader Methods
process.StandardOutput.BaseStream.BeginRead(...) is a potential substitute for your readline, and that will not wait for a line ending however you'd need to know what terminates the output to figure out when not to start wait for the next chunk of data
As Rune said, you can access directly to the output stream of the process (process.StandardOutput) and read from there (if you don't want to wait until a line break is entered into the console app), but this means that you need to check periodically for new data.
To interact with the application, you can just write to the StandardInput of the process (create a StreamWriter that writes to the process.StandardInput).
A nice sample of writing to it is on the MSDN documentation (http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspx).
Hope this helps
You need to use the synchronous read method and handle any necessary threading yourself. The below code won't tell you that input is expected, but you will be able to detect that a prompt is displayed.
char[] b = new char[1024];
while (!process.HasExited) {
int c = process.StandardOutput.Read(b, 0, b.Length);
context.Response.Write(b, 0, c);
Thread.Sleep(100);
}