How do make a call to a ruby script and pass some parameters and once the script is finished return the control back to the c# code with the result?
void runScript()
{
using (Process p = new Process())
{
ProcessStartInfo info = new ProcessStartInfo("ruby C:\rubyscript.rb");
info.Arguments = "args"; // set args
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
string output = p.StandardOutput.ReadToEnd();
// process output
}
}
Just to fill smaller gaps I've implemented the same functionallity with ability to access OutputStream asynchronously.
public void RunScript(string script, string arguments, out string errorMessage)
{
errorMessage = string.empty;
using ( Process process = new Process() )
{
process.OutputDataReceived += process_OutputDataReceived;
ProcessStartInfo info = new ProcessStartInfo(script);
info.Arguments = String.Join(" ", arguments);
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo = info;
process.EnableRaisingEvents = true;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
errorMessage = process.StandardError.ReadToEnd();
}
}
private void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
using ( AutoResetEvent errorWaitHandle = new AutoResetEvent(false) )
{
if ( !string.IsNullOrEmpty(e.Data) )
{
// Write the output somewhere
}
}
}
Related
I am open some process and read its output and I want to pass this function another param:
public void Start(string fileName, string arguments)
{
Process process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
}
private void OutputHandler(object sender, DataReceivedEventArgs e)
{
App.Current.Dispatcher.Invoke((Action)delegate
{
string line = e.Data;
if (line != null)
{
}
});
}
I want to run python script but my problem is that i get all the output at once at the end and not line by line (my script print the time 10 times and sleep for 1 second after each time).
This is my code:
static void Main(string[] args)
{
string cmd = #"C:\test.py";
string pythonPath = #"C:\python.exe";
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = pythonPath;//cmd is full path to python.exe
start.Arguments = cmd;//args is path to .py file and any cmd line args
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
while (!process.StandardOutput.EndOfStream)
{
string result = process.StandardOutput.ReadLine();
Console.Write(result);
}
}
}
}
UPDATE
string cmd = #"C:\test.py";
string pythonPath = #"C:\Python37\python.exe";
Process process = new Process();
process.StartInfo.FileName = "python";
process.StartInfo.Arguments = cmd;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
private static void OutputHandler(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
Python script
import time
from datetime import datetime
count = 0
while count < 3:
print(datetime.now())
time.sleep(1)
count += 1
print('DONE')
I start a few processes and I want to know which process called the OutputHandler, but I can’t get any information about the sending process.
When I try to read a property, it always throws a InvalidOperationException
void ExecString()
{
using (Process process = new Process())
{
process.StartInfo.FileName = executeExe;
process.StartInfo.Arguments = string.Format("{0}/{1}#{2} #{3}", parameter0, parameter1, parameter2, parameter3);
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.EnableRaisingEvents = true;
process.OutputDataReceived += OutputHandler;
process.Start();
process.BeginOutputReadLine();
}
}
void OutputHandler(object sendingProcess, DataReceivedEventArgs output)
{
try
{
OutputText = output.Data;
var tmpProcess = (Process)sendingProcess;
var testId = tmpProcess.Id; // Throw Exception
}
catch (InvalidOperationException e)
{
OutputText = e.Message;
}
}
Could you try this, It may help you;
Process currentProcess = Process.GetCurrentProcess();
var pid = currentProcess.Id;
Running a Git diff gets stuck, till killed when running as a System.Diagnostics.Process.
Code:
class Program
{
static void Main(string[] args)
{
ProcessStartInfo pInfo = new ProcessStartInfo();
pInfo.FileName = "git.exe";
pInfo.Arguments = "diff --name-only --exit-code V2.4-Beta-01 HEAD";
pInfo.WorkingDirectory = #"C:\Git";
pInfo.UseShellExecute = false;
pInfo.CreateNoWindow = true;
pInfo.RedirectStandardError = true;
pInfo.RedirectStandardOutput = true;
Process p = new Process();
p.StartInfo = pInfo;
p.Start();
p.WaitForExit(10000);
if (!p.HasExited)
{
p.Kill();
Console.WriteLine("Killed!!!");
}
Console.WriteLine(p.StandardOutput.ReadToEnd());
Console.WriteLine(p.StandardError.ReadToEnd());
Console.ReadLine();
}
}
How to avoid this and make the program exists normally without expiring its timeout?
The problem is that someone has to consume the stdout buffer or it will get filled and the process gets stucked (see explanation here). The diff I was trying retrieved 983 lines, which was causing a buffer overflow.
The following is a solution to my problem:
class Program
{
static void Main(string[] args)
{
ProcessStartInfo pInfo = new ProcessStartInfo();
pInfo.FileName = "git.exe";
pInfo.Arguments = "diff --name-only --exit-code V2.4-Beta-01 HEAD";
pInfo.WorkingDirectory = #"C:\Git";
pInfo.UseShellExecute = false;
pInfo.CreateNoWindow = true;
pInfo.RedirectStandardError = true;
pInfo.RedirectStandardOutput = true;
string output = string.Empty;
Process p = new Process();
p.StartInfo = pInfo;
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
output += e.Data + Environment.NewLine;
}
});
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
p.Close();
Console.WriteLine(output);
Console.ReadLine();
}
}
I have found many examples of coding on how to execute cmd.exe and execute a command, and execute even nslookup and interact, but the problem I am having is with a particular dos program that when it starts, it does not stop "outputting". here is some code and I will put a comment and the errors I get from C#
Here is how I have it setup in a more advanced way so I can receive output from the program on events
public void StartApplication(string appNameAndPath)
{
StreamReader outputStream;
Process p = new Process();
p.StartInfo.FileName = appNameAndPath;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = false;//for now just so I can see it
p.Start();
//here is my advanced example
if(advanced == true)
{
outputStream = p.StandardOutput;
DoReadOutPut();
}
else
{//here is a simple example
while (p.StandardOutput.ReadLine() != null) //this hangs here until the application exists
{
txt += (p.StandardOutput.ReadLine());
}
}
}
void DoReadOutput()
{
outputStream.BaseStream.BeginRead( readOutputBuffer, 0, readOutputBuffer.Length, new AsyncCallback( OnReadOutputCompleted ), null );
//this does sometimes fire but only with 0 bytes, on other dos programs it would say Memory read not allowed
}
void OnReadOutputCompleted( IAsyncResult result )
{
int cbRead = outputStream.BaseStream.EndRead( result );
ProcessOutput( readOutputBuffer, cbRead );
DoReadOutput();
}
private void ProcessOutput(byte[] buffer, int cbRead)
{
string text = p.StartInfo.StandardOutputEncoding.GetString(buffer, 0, 10000); //this is where it hangs until the program exits or is not writing anymore
this.Invoke((Action)delegate
{
SetTextBoxValue(text);//im doing this because im on another thread otherwise textBox1.Text - text"
});
}
I do not want to have to use API and GetText and create an engine to ReadLastLine, can anyone help me with this? I suppose you would want an example exe, creating a C# application that while(true){Console.WriteLine("bla");} would suffice as the example exe but not the exe I am having trouble with. The exe takes over the dos window and has an "old school interface"
async/await can help here....
await Exec(yourExe,parameters);
Task Exec(string exe,string args)
{
var tcs = new TaskCompletionSource<object>();
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = exe;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.Arguments = args;
var proc = Process.Start(psi);
proc.OutputDataReceived += (s, e) =>
{
this.Invoke((Action) (()=>richTextBox1.AppendText(e.Data + Environment.NewLine)));
};
proc.Exited += (s, e) => tcs.SetResult(null);
proc.EnableRaisingEvents = true;
proc.BeginOutputReadLine();
return tcs.Task;
}
You need to handle callback events to read streams:
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
Process proc = new Process();
proc.StartInfo = startInfo;
proc.ErrorDataReceived += new DataReceivedEventHandler(DataReceiveHandler);
proc.OutputDataReceived += new DataReceivedEventHandler(DataReceiveHandler);
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
Code borrowed from this post