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
Related
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.
In C#, I can start a process with
process.start(program.exe);
How do I tell if the program is still running, or if it closed?
MSDN System.Diagnostics.Process
If you want to know right now, you can check the HasExited property.
var isRunning = !process.HasExited;
If it's a quick process, just wait for it.
process.WaitForExit();
If you're starting one up in the background, subscribe to the Exited event after setting EnableRaisingEvents to true.
process.EnableRaisingEvents = true;
process.Exited += (sender, e) => { /* do whatever */ };
Process p = new Process();
p.Exited += new EventHandler(p_Exited);
p.StartInfo.FileName = #"path to file";
p.EnableRaisingEvents = true;
p.Start();
void p_Exited(object sender, EventArgs e)
{
MessageBox.Show("Process exited");
}
Be sure you save the Process object if you use the static Process.Start() call (or create an instance with new), and then either check the HasExited property, or subscribe to the Exited event, depending on your needs.
Assign an event handler to the Exited event.
There is sample code in that MSDN link - I won't repeat it here.
Take a look at the MSDN documentation for the Process class.
In particular there is an event (Exited) you can listen to.
I have to run 3 processes sequentially, one after other. The second process must start after first process' completion.
I work in C#. I have used Process.Start() method, Where it kicks on all at same time.
Can anyone help me.
One way of doing it adding a handler for the Exited event of the first process, and then starting the second process from there.
void StartProcessOne() {
Process p = Process.Start("foo", "bar");
p.Exited += (sender, e) => StartProcessTwo();
p.Start();
}
void StartProcessTwo() {
Process p = Process.Start("foo2", "bar2");
p.Exited += (sender, e) => StartProcessThree();
p.Start();
}
...
You can also use the WaitForExit() method, which waits for the process to end before continuing execution of your code. Note, however, this makes your own process stop execution until the other process terminates. This can leave you with an unresponsive user interface and such, which can be quite undesirable.(source)
Process.Start("yourprogram.exe").WaitForExit();
Process.Start("yournextprogram.exe").WaitForExit();
and so on...
You can accomplish this by responding to the Process.Exited event.
You should use this approach instead of WaitForExit() because the latter will block your program from responding to user input, etc...
private int n = 0;
private void StartAProcess()
{
Process process = new Process {
StartInfo = {FileName = "cmd.exe", Arguments = "pause"},
EnableRaisingEvents = true};
process.Exited += process_Exited;
process.Start();
n++;
}
void process_Exited(object sender, EventArgs e)
{
if (n < 3) StartAProcess();
}
try this code for each process
Process.WaitForExit()
http://msdn.microsoft.com/en-us/library/aa326953(v=VS.71).aspx
If you are using .NET 4 you could use the System.Threading.Tasks API. If your graph gets more complex you may get some mileage from http://pdag.codeplex.com (I must confess, this is my work).
You need to do a process.join() to wait for the first process to complete before submitting the next one. However, the bigger question is why you are using Process.Start() - for asynchronous tasks - when you actually want them to run synchronously? Just calling:
a();
b();
c();
will run them one after another.
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();
}
I have a process, i can start, and hide working fine, but i want to read from the console program, when i runs, not after, i tried to run a timer, anbd read at the tick, but my program just crashes and when it not do, i get nothing at all.
startInfo= new ProcessStartInfo("cmd.exe");
startInfo.Arguments ="/C uus.exe "+ arg.ToString();
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
this.timer1.Enabled=true;
this.listBox1.Items.Clear();
p= Process.Start(startInfo);
Application.DoEvents();
void Timer1Tick(object sender, EventArgs e)
{
string str="";
str=p.StandardOutput.ReadLine();
if(str != null)
{
this.Text=str.ToString();
this.listBox1.Items.Add(str);
}
Application.DoEvents();
}
So what do i do to solve this?
Update:
I tried bender suggestion
now My program don't crash anymore, but also don't recvie any data
proc.StartInfo.UseShellExecute=false;
proc.StartInfo.CreateNoWindow=true;
proc.StartInfo.RedirectStandardOutput=true;
proc.StartInfo.RedirectStandardError=true;
proc.StartInfo.FileName="uus.exe";
proc.StartInfo.Arguments=arg;
proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(SortOutputHandler);
proc.Start();
proc.BeginOutputReadLine();
void SortOutputHandler(object o,System.Diagnostics.DataReceivedEventArgs e)
{
string str="";
string str2="";
str=e.Data.ToString();
if(str!=null && str!="")
{
this.listBox1.Items.Add(str.ToString());
this.Text=str.ToString();
}
str2=proc.StandardOutput.ReadLine();
if(str2!=null && str2!="")
{
this.lsw1.Items.Add(str2.ToString());
}
}
hmm?
Update:
I have changed the handler, because i have being tell, it can't do it, that it wil be cross thread operation, usualyy i wille have get an error if it was.
private delegate void TextAdderDelegate(string str);
void TextAdder(string str)
{
if(this.lsw1.InvokeRequired==true)
{
Invoke(new TextAdderDelegate(TextAdder),new object[] {str});
}
else
{
this.lsw1.Items.Add(str);
}
}
void SortOutputHandler(object o,System.Diagnostics.DataReceivedEventArgs e)
{
string str="";
if(e!=null)
{
if(e.Data!=null)
{
str=e.Data.ToString();
}
}
TextAdder(str);
}
The problem is that you're running on one thread and trying to write using another. When you created your background thread using the Timer's tick event, it can't have frontend user input.
Perhaps if you explained the big picture of what you're trying to accomplish, we can better help you.
In the meantime, you might want to create threadsafe writes. This article will help you to understand the problem and solution to writing to form controls on different threads.
You may create the Process instance explicitly (e.g. new Process)and use the OutputDataReceived event, the method BeginOutputReadLine() and, when finished CancelOutputRead() for that.
The event OutputDataReceived will be repeatedly called asynchronously from a different thread as soon output data is available.
I assume you get an 'thread cross exception', this may be caused because you're updating your form controls on an other thread then the UI thread.