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;
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 have a crash in Event Viewer with this:
Exception Info: System.ArgumentOutOfRangeException
at System.Text.StringBuilder.ToString()
at XXX.BrainActions+<>c__DisplayClass11_0.<runApp>b__0(System.Object,
System.EventArgs)
The offending code is this, why is StringBuilder causing this exception?
Process process = new Process();
StringBuilder builder = new StringBuilder();
try
{
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.FileName = filename;
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Themes.getInstance().getScriptPath();
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.EnableRaisingEvents = true;
process.Exited += new EventHandler((object sender, System.EventArgs e) => {
string consoleOutput = builder.ToString();
if (!String.IsNullOrWhiteSpace(consoleOutput))
{
Log.INFO("XXX", String.Format("Console output: {0}", builder.ToString()));
}
processesRunning.Remove(process);
if (callbacks != null)
{
callbacks.ActionCompleted(action);
if (processesRunning.Count == 0)
{
callbacks.AllActionsCompleted();
}
}
});
process.Start();
process.PriorityClass = ProcessPriorityClass.High;
process.OutputDataReceived += (sender, args) => builder.Append(args.Data);
process.ErrorDataReceived += (sender, args) => builder.Append(args.Data);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
processesRunning.Add(process);
}
catch (Exception e)
{
}
StringBuilder is used to basically get the output of the external process and log it to the console using Log4net which is basically wrapped in the Log() function. Any ideas? Note that this crash rarely happens I've only seen it once but once is a reason to fix it.
Iam currently starting batch-script with this method (async)
private void executor(string path)
{
//Vars
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo(path);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
//Handle Output
});
process.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
{
//Handle Errors
});
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
//Handle Exit
}
The user chose the script (which will be performed by my program) and can run it. But the user can chose a script, which contains a pause-Command.
This will cause a deadlock.
How can I check that the script need a user-input?
I found a solution. Iam not longer use the OutputDataReceived-Event.
Here is my new (well-working) code:
private void executor(string path)
{
//Vars
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo(path);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
{
//Handle Errors
});
process.BeginErrorReadLine();
//Try read while script is running (will block thread until script ended)
while (!process.HasExited)
while (!process.StandardOutput.EndOfStream)
{
char c = (char)process.StandardOutput.Read();
if (c == '\n')
{
_outputList.Add(_lastOutputStringBuilder.ToString());
_lastOutputStringBuilder.Clear();
//Handle Output
}
else
_lastOutputStringBuilder.Append(c);
}
//Handle Exit
}
With this code, I can store the last line (which must not end with a linebreak) and can check it for lines like "Press a key ..."
When you call the RedirectCommandStream in the code below it works perfectly in a console application, however in a wpf application it misses out the standard output data and some of the standard error output. The string builder that is outputed from the method is then used to display on the wpf application.
Can someone please help, been stuck on this for a long time?
class ProcessStreamRedirection
{
private static StringBuilder OutputBuilder = null;
public static StringBuilder RedirectCommandStreams(string FileName,string Arguments)
{
Process Process;
Process = new Process();
Process.StartInfo.FileName = FileName;
Process.StartInfo.Arguments = Arguments;
Process.StartInfo.UseShellExecute = false;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.CreateNoWindow = false;
Process.OutputDataReceived += new DataReceivedEventHandler(DataHandler);
OutputBuilder = new StringBuilder();
Process.StartInfo.RedirectStandardError = true;
Process.ErrorDataReceived += new DataReceivedEventHandler(DataHandler);
OutputBuilder.AppendLine(string.Format("Starting process: {0} {1}", Process.StartInfo.FileName ,Process.StartInfo.Arguments));
Process.Start();
Process.BeginOutputReadLine();
Process.BeginErrorReadLine();
Process.WaitForExit();
if (OutputBuilder.Length > 0)
{
OutputBuilder.AppendLine(string.Format("Output:\n{0}\n", OutputBuilder));
}
Process.Close();
return OutputBuilder;
}
private static void DataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{
OutputBuilder.AppendLine(outLine.Data);
}
}
}
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
}
}
}