strange behavior when running process using process class vs cmd c# - c#

I want to run Iperf via c#
when running via cmd everything works fine and fast
but I run it via c# using this code :
public void RunProcess(string FileName, string Arguments, bool EventWhenExit )
{
process = new Process();
process.EnableRaisingEvents = true;
process.OutputDataReceived += new DataReceivedEventHandler(OnDataReceivedEvent);
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.LoadUserProfile = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = FileName; // Gets or sets the application or document to start.
process.StartInfo.Arguments =Arguments;//Gets or sets the set of command-line arguments to use when starting the application
Thread.Sleep(1000);
if (EventWhenExit)
{
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(myprocess_Exited);/*New line */
}
process.Start();
process.BeginOutputReadLine();
PID = process.Id;
}
private void myprocess_Exited(object sender, EventArgs e)
{
process.Refresh();
Thread.Sleep(2000);
onProcessEnd(this, "ENDOF " + Proc.ToString());
Console.WriteLine("Process exsiting ");
}
private void OnDataReceivedEvent(object sender, DataReceivedEventArgs e)
{
string OutputFromProcess = e.Data;
//fire event to event handler class for further use
onDataOutputFromProcess(this, OutputFromProcess, Proc.ToString());
}
I get wrong strange behavior :
when running 1 stream (those of you who use Iperf will know...) every works fine in console and my application (winform)
but I run 3 streams and above , my application wont go over and than just hangs when it should exit
what can be the problem ?
what can be a good work around this problem ?

First you should avoid using Thread.Sleep(x) at any cost.
And i assume you are not using a backgroundWorker or a new Thread to execute the IPerf processes?
I think the backgroundworker would work well for you. Take a look here
In addition:
A cmd program is in most cases very linear.
A WinForm program not. You have to sepereate GUI and Work-Thread.
the GUI is only for Input and Display. Everthing else you should do in another Thread, because otherwise you will block the GUI.

Related

About C# Process Class:I can start some processes but another can not open [duplicate]

This question already has answers here:
How do I start a process from C#?
(13 answers)
Closed 6 years ago.
Can anyone help me? O(∩_∩)O
Today I meet a question that I want to use a program maybe a player and I need log the data(BCI EEG) from the user.So I try to use the Process Class to Start a ConsoleApplication in an WindowsApplication.
I create a Simple WindowsApplication to have a try my idea.
But it not works,I also try to use the Process Class to Start other Application It' Ok.When I Start my own program that is a ConsoleApplication it not works.
public partial class Form1 : Form
{
Process myProcess = new Process();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
myProcess.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
myProcess.StartInfo.FileName = "D:\\EEG\\Emotiv Xavier TestBench v3.0.0.41\\EmotivXavierTestBench.exe";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
//System.Console.WriteLine("Hello World!");
//MessageBox.Show("button1.Click was raised.");
}
This TestBench program can open .But why the program I create doesn't work?
D:\temp\EmotivConnection\Debug\EmotivConnection.exe
So you've run the application, but don't allow to create any console window by
myProcess.StartInfo.CreateNoWindow = true;
And so you see nothing (the application runs however). Probably, you want to re-direct the output (and show it in, say, MyTextBox instead of console window)
private void button1_Click(object sender, EventArgs e) {
// Process is IDisposable, so wrap it into using
using (Process myProcess = new Process()) {
myProcess.StartInfo.UseShellExecute = false;
// You can start any process, HelloWorld is a do-nothing example.
myProcess.StartInfo.FileName =
//"cmd.exe"; // <- standard test
"D:\\EEG\\Emotiv Xavier TestBench v3.0.0.41\\EmotivXavierTestBench.exe";
myProcess.StartInfo.CreateNoWindow = true;
// Crucial: we want to see the output in MyTextBox,
// not in the standard console (which is hidden by "CreateNoWindow = true")
myProcess.StartInfo.RedirectStandardOutput = true;
// You may want this as well
//myProcess.StartInfo.RedirectStandardError = true;
myProcess.Start();
myProcess.WaitForExit();
// Do not forget to put MyTextBox on the form
// Read the output ("Hello World") in the MyTextBox
MyTextBox.Text = myProcess.StandardOutput.ReadToEnd();
}
}
You are calling
myProcess.StartInfo.CreateNoWindow = true;
have you checked, if your task manager contains your program?
I assume it is actually running but in the same window as your current app.
About CreateNoWindow:
"true if the process should be started without creating a new window to contain it; otherwise, false. The default is false."
Source: MSDN
This could help you aswell:
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
.NET - WindowStyle = hidden vs. CreateNoWindow = true?

How to open .exe files from C# one by one? [duplicate]

I've an application which does
Process.Start()
to start another application 'ABC'. I want to wait till that application ends (process dies) and continue my execution. How can I do it?
There may be multiple instances of the application 'ABC' running at the same time.
I think you just want this:
var process = Process.Start(...);
process.WaitForExit();
See the MSDN page for the method. It also has an overload where you can specify the timeout, so you're not potentially waiting forever.
Use Process.WaitForExit? Or subscribe to the Process.Exited event if you don't want to block? If that doesn't do what you want, please give us more information about your requirements.
I do the following in my application:
Process process = new Process();
process.StartInfo.FileName = executable;
process.StartInfo.Arguments = arguments;
process.StartInfo.ErrorDialog = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
process.Start();
process.WaitForExit(1000 * 60 * 5); // Wait up to five minutes.
There are a few extra features in there which you might find useful...
You could use wait for exit or you can catch the HasExited property and update your UI to keep the user "informed" (expectation management):
System.Diagnostics.Process process = System.Diagnostics.Process.Start("cmd.exe");
while (!process.HasExited)
{
//update UI
}
//done
I had a case where Process.HasExited didn't change after closing the window belonging to the process. So Process.WaitForExit() also didn't work. I had to monitor Process.Responding that went to false after closing the window like that:
while (!_process.HasExited && _process.Responding) {
Thread.Sleep(100);
}
...
Perhaps this helps someone.
Process.WaitForExit should be just what you're looking for I think.
Referring to the Microsoft example:
[https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.enableraisingevents?view=netframework-4.8]
Best would be to set:
myProcess.EnableRaisingEvents = true;
otherwiese the Code will be blocked.
Also no additional properties needed.
// Start a process and raise an event when done.
myProcess.StartInfo.FileName = fileName;
// Allows to raise event when the process is finished
myProcess.EnableRaisingEvents = true;
// Eventhandler wich fires when exited
myProcess.Exited += new EventHandler(myProcess_Exited);
// Starts the process
myProcess.Start();
// Handle Exited event and display process information.
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {myProcess.ExitTime}\n" +
$"Exit code : {myProcess.ExitCode}\n" +
$"Elapsed time : {elapsedTime}");
}
Like Jon Skeet says, use the Process.Exited:
proc.StartInfo.FileName = exportPath + #"\" + fileExe;
proc.Exited += new EventHandler(myProcess_Exited);
proc.Start();
inProcess = true;
while (inProcess)
{
proc.Refresh();
System.Threading.Thread.Sleep(10);
if (proc.HasExited)
{
inProcess = false;
}
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
inProcess = false;
Console.WriteLine("Exit time: {0}\r\n" +
"Exit code: {1}\r\n", proc.ExitTime, proc.ExitCode);
}
Try this:
string command = "...";
var process = Process.Start(command);
process.WaitForExit();

Why does the Process.Exited event fire two times?

I am writing an application in C# to download images using the Process class and wget.exe.
I want to handle the Process.Exited event without calling WaitForExit because calling WaitForExit hangs my UI. To work around this, I have tried many techniques like calling both Process.Start() and Process.WaitForExit() on another thread, using a BackgroundWorker etc. Still, my UI hangs at some level. So now I want simply handle the Process.Exited event without WaitForExit.
My code is:
bool processComplete = false;
Process process = new Process();
private void Start()
{
process.StartInfo.FileName = "path of wget";
process.StartInfo.Arguments = "arguments for downloading images";
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(Process_Complete);
process.StartInfo.WindowStyle = ProcessWindowStyle.Hide;
process.Start();
}
private void Process_Complete(object sender, EventArgs e)
{
processComplete = true;
}
After starting the process, the Process.Exited event fires two times. First, while process is going on in between if some times downloading become slow(if images are more than 1000 etc ow at the starting only it fires process.exited event) and then after all images are downloaded,
I would expect the Process.Exited event to fire once. Why is it firing twice?
Faced the same issue.
I guess it's somehow related to accessing process members from different threads (in my case at least), 'cause from the log it's clear that handler is called from different threads.
Anyway, my solution was to unsubscribe from event in event handler:
bool processComplete = false;
Process process = new Process();
private void Start()
{
process.StartInfo.FileName = "path of wget";
process.StartInfo.Arguments = "arguments for downloading images";
process.EnableRaisingEvents = true;
process.Exited += Process_Complete;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hide;
process.Start();
}
private void Process_Complete(object sender, EventArgs e)
{
process.Exited -= Process_Complete;
processComplete = true;
}
I think alternative solution might be to synchronize access to process instance (using lock for example).

cmd.exe style application written in C#

I am trying to get the results from any DOS-based application, effectively letting C# operate it as if it were a user.
I can get it to execute a command, and then show the output. The problem is knowing when the output has ended! For example, if I go start/run "cmd.exe", type "D:", then "cd D:\", and then "tree", it outputs my folder structure on the D drive, and then allows me to type my next command (only after it's finished printing the list).
However I can't find a way in code to get it to realise it's finished, and should allow the next command (basically when cmd.exe starts blinking your cursor).
public Process p = null;
private void Form1_Load(object sender, System.EventArgs e)
{
ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
procStarter.RedirectStandardOutput = true;
procStarter.RedirectStandardInput = true;
procStarter.UseShellExecute = false;
procStarter.CreateNoWindow = true;
p = Process.Start(procStarter);
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
p.Close();
}
private void btnSend_Click(object sender, System.EventArgs e)
{
p.StandardInput.WriteLine("D:");
p.StandardInput.WriteLine(#"cd D:\");
txtOutput.Text = SendCommand(txtInput.Text);
}
private string SendCommand(string cmd)
{
p.StandardInput.WriteLine(cmd);
return p.StandardOutput.ReadToEnd();
}
In SendCommand(string cmd), if I run p.StandardOutput.ReadToEnd(), as per the code above, it hangs forever, presumably waiting for the application to close?
If I loop through p.StandardOutput.ReadLine(), it shows all the text (including the "D:\>" just before where the blinking cursor would then be, however it doesn't realise it's the end, calls ReadLine again, and hangs in a smiliar fashion to ReadToEnd. A dirty workaround would be to treat it as the end of the response if the current line ends with ">", however that falls apart if a line ends like that anywhere in the response.
I've tried looping through the stream character by character, and there's no special character sent at the end.
Any ideas?
Note: My ultimate goal is to provide a light library I can use for executing any DOS executable (which may require several typed commands passed to it, not just the one off arguments passed via command line on opening), parsing the results returned with a regex template, and returning the extracted result. I figured if I can effectively re-implement the cmd.exe in a windows application, then such a library will be possible.
Thanks,
Lee
I suspect that your approach doesn’t work. cmd.exe is not going to communicate to you via StandardOutput when or whether the command you ran has finished or not. (I should point out though that this doesn’t stop you from running multiple commands. You can probably just send the command lines and don’t actually need to wait for it to finish.)
Perhaps a more suitable approach might be not to use cmd.exe at all. Instead, use Process.Start() to run each individual command. Then you can use StandardOutput.ReadToEnd() and it will finish when the process is finished, and you can run the next one.
I agree with Timwi, But see if something like below helps
ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
procStarter.RedirectStandardOutput = true;
procStarter.RedirectStandardInput = true;
procStarter.UseShellExecute = false;
procStarter.CreateNoWindow = true;
procStarter.WorkingDirectory = #"D:\";
procStarter.Arguments = "/C dir";
Process p = Process.Start(procStarter);
string output = p.StandardOutput.ReadToEnd();
/C command line to cmd.exe will terminate cmd.exe once the work is done. You can also use p.Exited (exited event) to know when it happens.
However it will not keep the cmd.exe always running. But do you really need to keep it running?
If you're looking for 'how to wait till the spawned process terminates', Process.WaitForExit is what should do the trick.
You could spawn a new shell for each "command".
About a year ago I wrote a telnet server for windows that allowed the remote user to issue commands against cmd.exe. Maybe you can use it as a starting point for your own project.
Get the code on my blog
By reading the output asynchronous I have gotten this to work (aleast almost) like you described:
public Process p = null;
private void Send_Click(object sender, System.EventArgs e)
{
p.StandardInput.WriteLine("D:");
p.StandardInput.WriteLine(#"cd D:\");
p.StandardInput.WriteLine(txtInput.Text);
}
private void Form1_Load_1(object sender, EventArgs e)
{
ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
procStarter.RedirectStandardOutput = true;
procStarter.RedirectStandardInput = true;
procStarter.UseShellExecute = false;
procStarter.CreateNoWindow = true;
p = Process.Start(procStarter);
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
p.BeginOutputReadLine();
}
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
addTextToOutput(e.Data);
}
private void addTextToOutput(string text)
{
if (txtOutput.InvokeRequired)
{
addTextCallback cb = new addTextCallback(addTextToOutput);
this.Invoke(cb, new Object[] { text });
}
else
{
txtOutput.Text += text+ System.Environment.NewLine;
}
}
delegate void addTextCallback(String text);
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
p.Close();
}

Run code when current process terminates?

Is there a way to run a bit of code when the current process is getting terminated?
I want to log some stuff when a process terminates (either through external means - eg killing it - or quitting in the application itself).
We're talking about a Console application written in c#.
Thanks!
Have a look here: atexit, exit delegate in c#
I am not sure, but something similar would help
Process process = new Process();
.
.
process.Exited += new EventHandler(myProcess_Exited);
process.Start();
private void myProcess_Exited(object sender, System.EventArgs e)
{
eventHandled = true;
customAction(); // your logging stuff here
}
public void customAction()
{
//
}
have a look at: Process.Exited Event

Categories