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 ..."
Related
Im running an exe through process in my c# program, i want the process to be completely invisible without the console of it popping up.
This is my code
Process process2 = new Process();
process2.StartInfo.FileName = "cmd.exe";
process2.StartInfo.UseShellExecute = false;
process2.StartInfo.CreateNoWindow = true;
process2.StartInfo.RedirectStandardOutput = true;
process2.StartInfo.RedirectStandardError = true;
process2.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process2 = Process.Start(path3);
even with this code the console window still opens and shows, any help will be appreciated :)
Using
UseShellExecute = false; CreateNoWindow = true;
Should hide the process although it depends on the path in which you are opening, if the process has a force show
Try the following:
private void RunCmd(string exePath, string arguments = null)
{
//create new instance
ProcessStartInfo startInfo = new ProcessStartInfo(exePath, arguments);
startInfo.Arguments = arguments; //arguments
startInfo.CreateNoWindow = true; //don't create a window
startInfo.RedirectStandardError = true; //redirect standard error
startInfo.RedirectStandardOutput = true; //redirect standard output
startInfo.RedirectStandardInput = false;
startInfo.UseShellExecute = false; //if true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.ErrorDialog = false;
//create new instance
using (Process p = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
{
//subscribe to event and add event handler code
p.ErrorDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Error: " + e.Data);
}
};
//subscribe to event and add event handler code
p.OutputDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Output: " + e.Data);
}
};
p.Start(); //start
p.BeginErrorReadLine(); //begin async reading for standard error
p.BeginOutputReadLine(); //begin async reading for standard output
//waits until the process is finished before continuing
p.WaitForExit();
}
}
See also this post.
I fixed it by renaming the window instead ty for all your help
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;
I am currently struggling with bringing existing data in batch file to C# window form
The whole objective is getting a result lively from batch file to C# rich text box but I am keep getting failure of doing it.
The procedure works like click button->run batch file secretly->C# gets data lively->display in rich text box
I was successful to run a batch file but it runs in another new CMD causing hanging problem during debugging.
I would like to know whether anyone can wrote me a code to overcome such problem. Hope for the best answer
ProcessStartInfo cmd = new ProcessStartInfo();
Process process = new Process();
cmd.FileName = #"cmd";
cmd.UseShellExecute = false;
cmd.RedirectStandardError = true;
cmd.RedirectStandardInput = true;
cmd.RedirectStandardOutput = true;
cmd.CreateNoWindow = true;
process.EnableRaisingEvents = false;
process.StartInfo = cmd;
process.Start();
process.StandardInput.Write(#"cd C:\Users\%username%\Desktop\Claymore's Dual Ethereum+Decred_Siacoin_Lbry_Pascal AMD+NVIDIA GPU Miner v11.0" + Environment.NewLine);
process.StandardInput.Write(#"EthDcrMiner64.exe -allpools 1 -epool asia1.ethereum.miningpoolhub.com:20535 -ewal AJStudio.AJStudio001 -epsw x -esm 2" + Environment.NewLine);
process.StandardInput.Close();
string result = process.StandardOutput.ReadToEnd();
StringBuilder sb = new StringBuilder();
sb.Append("[result info]" + DateTime.Now + "\r\n");
sb.Append(result);
sb.Append("\r\n");
richTextBox1.Text = sb.ToString();
process.WaitForExit();
process.Close();
To get real-time feedback from Process, use OutputDataReceived and ErrorDataReceived events. Something like this:
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.OutputDataReceived += Process_OutputDataReceived;
process.ErrorDataReceived += Process_ErrorDataReceived;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data == null) return;
log("ERROR: " + e.Data);
}
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data == null) return;
log(e.Data);
}
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.
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