I know little about C#.
I am trying to display a progressbar with the status of the background command line program.
After google examples of progressbar and run process in c#, so I'm trying to start a BackgroundWorker in the Windows Form, and run the command line program in the BackgroundWorker. I want to parse the command line's output to get the progress
percentage and display it to the progress bar.
The command line program is a console program, it will output periodically its current status of progress.
But it seems it did not work. I can't readline any lines of the process's standard output.
Is there anything I missed?
Here is the raw code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Diagnostics;
using System.IO;
public class DemoForm : Form
{
private BackgroundWorker backgroundWorker1;
private Button loadButton;
private ProgressBar progressBar1;
public DemoForm()
{
InitializeComponent();
backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(
this.backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new System.ComponentModel.RunWorkerCompletedEventHandler(
this.backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new System.ComponentModel.ProgressChangedEventHandler(
this.backgroundWorker1_ProgressChanged);
}
private void loadButton_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
this.loadButton.Enabled = false;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string status;
Process p = new Process();
p.StartInfo.FileName = "xx.exe";
p.StartInfo.Arguments = "-q -r test.cap -p";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.CreateNoWindow = true;
p.OutputDataReceived += this.p_OutputDataReceived;
p.EnableRaisingEvents = true;
p.Start();
p.BeginOutputReadLine();
/*
while((status = p.StandardOutput.ReadLine()) != null)
{
Console.WriteLine(status);
string[] words = status.Split(' ');
int offset = Convert.ToInt32(words[0]);
int size = Convert.ToInt32(words[1]);
int percentComplete = 100 * offset / size;
MessageBox.Show(words[0], words[1]);
backgroundWorker1.ReportProgress(percentComplete);
}
Console.WriteLine("wait for exit!");
StreamReader myStreamReader = p.StandardOutput;
status = myStreamReader.ReadLine();
Console.WriteLine(status);
Console.WriteLine("wait for exit!");
*/
p.WaitForExit();
}
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
string status = e.Data;
Console.WriteLine("get events");
Console.WriteLine(status);
string[] words = status.Split(' ');
int offset = Convert.ToInt32(words[0]);
int size = Convert.ToInt32(words[1]);
int percentComplete = 100 * offset / size;
MessageBox.Show(words[0], words[1]);
backgroundWorker1.ReportProgress(percentComplete);
}
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
progressBar1.Value = 100;
if (e.Error == null) {
MessageBox.Show ("Demo", "Loading completed");
}
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.loadButton = new System.Windows.Forms.Button();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
/* load button */
this.loadButton.Location = new System.Drawing.Point(12, 12);
this.loadButton.Name = "loadButton";
this.loadButton.Size = new System.Drawing.Size(100, 23);
this.loadButton.TabIndex = 0;
this.loadButton.Text = "Load file";
this.loadButton.UseVisualStyleBackColor = true;
this.loadButton.Click += new System.EventHandler(this.loadButton_Click);
/* progress bar */
this.progressBar1.Location = new System.Drawing.Point(12, 50);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(100, 26);
this.progressBar1.TabIndex = 1;
/* Form */
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(133, 104);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.loadButton);
this.Name = "DemoForm";
this.Text = "DemoForm";
this.ResumeLayout (false);
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new DemoForm());
}
}
Or is there any better way to get a command line program's progress?
You have to set the WorkerReportsProgress property of your backgroundWorker to true in order to be able to report while your backgroundWorker is running:
backgroundWorker1.WorkerReportsProgress = true;
After manually flush the output of the command line program, problem solved.
fflush(stdout);
It's not clear why it's buffered even a line ended.
Building on what Kamyar was stating, you would need to then code a delegate to capture the progress of your backgroundWorker object using a UserState object. This could be any object really, but you use it to update other aspects of the GUI, in this case a status label...
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
private class Progress
{
public string Status { get; set; }
public Progress(string status)
{
Status = status;
}
}
//...
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(myWork)
{
if(backgroundWorker1.CancellationPending)
{
e.Cancel = true;
break;
}
int p = //...percentage calc
backgroundWorker1.ReportProgress(p, new Progress("My message...")));
}
e.Cancel = false;
}
void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
Progress p = (Progress)e.UserState;
lStatus.Text = p.Status;
progressBar.Value = e.ProgressPercentage;
}
This is just one method of implementing it though.
Thanks.
Related
i have write prog to get info about android devices
i using external process
create class apktool :
this code
namespace dream_tool
{
class apktool
{
public StringBuilder output = new StringBuilder();
public Process cmd = new Process();
public string RunExternalPing(string a)
{
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.Arguments = a;
cmd.EnableRaisingEvents = true;
cmd.OutputDataReceived +=
new DataReceivedEventHandler(cmd_OutputDataReceived);
//cmd.Exited += new EventHandler(cmd_Exited);
cmd.Exited += new EventHandler(Form1.instance.cmd_Exited);
cmd.Start();
cmd.BeginOutputReadLine();
cmd.WaitForExit();
// StreamWriter sw = cmd.StandardInput;
//sw.WriteLine(a);
// cmd.WaitForExit();
// sw.Close();
return a;
}
private void cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Form1 frm = new Form1();
if (!String.IsNullOrEmpty(e.Data))
{
output.Append(e.Data + Environment.NewLine);
}
cmd.CancelOutputRead();
}
}
}
and in the form this code
public partial class Form1 : Form
{
public static Form1 instance;
apktool a2;
Procees_adb a1 = new Procees_adb();
List<String> fullFileName;
public Form1()
{
InitializeComponent();
instance = this;
a2 = new apktool();
}
public void cmd_Exited(object sender, EventArgs e)
{
if (RCH_OUT.InvokeRequired)
{
RCH_OUT.Invoke(new EventHandler(delegate { RCH_OUT.Text = (a2.output.ToString()); }));
}
else
{
RCH_OUT.Text = (a2.output.ToString());
MessageBox.Show(a2.output.ToString());
}
if(IsDisposed)
{
a2.cmd.Dispose();
}
//cmd.Dispose();
}
private void button2_Click(object sender, EventArgs e)
{
a2.RunExternalPing("/c adb shell getprop ro.product.cpu.abi");
}
}
[when i press on button in first time i get info and that ok
1
if i press it again
it show me error on cmd.BeginOutputReadLine();
System.InvalidOperationException: 'An async read operation has already been started on the stream.'
enter image description here
the first problem solve by add cmd.CancelOutputRead();
to
private void cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
but now when press button second time the info Repeated
Such as that in the picture
enter image description here
I have a made a small tool which gets file size and name of the URL but it takes time (approx 4 seconds) when I run the code and enter a file URL it takes time for the user it will look like it is not working.
I want to show a progress bar until the data is received so that user may not think that the application is not working.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Multi_Tool
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
{
if (textBox1.Text == "")
{
MessageBox.Show("You have not typed the URL", "URL Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
string URL = textBox1.Text;
string filetype = URL.Substring(URL.LastIndexOf(".") + 1,
(URL.Length - URL.LastIndexOf(".") - 1));
FileType.Text = filetype.ToUpper();
string filename = URL.Substring(URL.LastIndexOf("/") + 1,
(URL.Length - URL.LastIndexOf("/") - 1));
namelabel.Text = filename;
System.Net.WebRequest req = System.Net.HttpWebRequest.Create(textBox1.Text);
req.Method = "HEAD";
System.Net.WebResponse resp = req.GetResponse();
long ContentLength = 0;
long result;
if (long.TryParse(resp.Headers.Get("Content-Length"), out ContentLength))
{
string File_Size;
if (ContentLength >= 1073741824)
{
result = ContentLength / 1073741824;
kbmbgb.Text = "GB";
}
else if (ContentLength >= 1048576)
{
result = ContentLength / 1048576;
kbmbgb.Text = "MB";
}
else
{
result = ContentLength / 1024;
kbmbgb.Text = "KB";
}
File_Size = result.ToString("0.00");
sizevaluelabel.Text = File_Size;
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Clear();
}
}
}
You can use a background worker to move your downloading to another thread and showing a progress bar until the data is received.
ProgressForm is a form which contains progress bar which you can show until data is downloaded
this.progressBar1 = new System.Windows.Forms.ProgressBar();
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(12, 30);
this.progressBar1.MarqueeAnimationSpeed = 1;
this.progressBar1.Maximum = 2500;
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(522, 23);
this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
this.progressBar1.TabIndex = 1;
//constructor
public frmProgress(string text)
{
this.Text = text;
InitializeComponent();
}
If you want to show value in your progress bar make sure to change the properties back to normal(which are set as marquee in answer as of now).But as you said it is going to take just 4 secs it would be good to use marquee
//Method to increment value of progress bar
public void PrgBarInc()
{
if (this.IsHandleCreated)
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(PrgBarInc));
}
else
{
prgBar.Increment("your val");
}
}
==============================Main UI class==============================
BackgroundWorker backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
//Add In your method which initiates download
public void PerformDownload()
{
ProgressForm = new frmProgress("your text");
ProgressForm.ShowInTaskbar = false;
backgroundWorker1.RunWorkerAsync();
ProgressForm.ShowDialog();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//perform service request
//if any of your task gets compeleted just call
//ProgressForm.PrgBarInc()
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ProgressForm.Close();
ProgressForm.Dispose();
}
Normally, you update the progress bar like this:
progressBar1.Value = N;
Wrapping it within BeginInvoke() makes the UI responsive:
Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progressBar1.Value = progressBar1.Value + 1;
//update in UI Thread
return null;
}), null);
Alright, so I've got this program I'm trying to write. No company is going to rely on it or anything, so I'm not too caring that the threading here is almost positively poor practice.
My issue is that none of the "Form Closing Events" that I have found on this site and on MSDN are firing for me.
In my code, I have very hopeful console outputs that will notify me if the code has been run, but none of the events that I've found do such.
Can someone slap me into the reality of what it takes to get this to work? I know I must me missing something simple here.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;
namespace CMDRunner
{
public partial class Form1 : Form
{
IDataObject clippy = Clipboard.GetDataObject();
String TClippy;
bool isRunning = true;
//Thread worker;
public Form1()
{
InitializeComponent();
try
{
TClippy = Clipboard.GetText();
}
catch (Exception e)
{
richTextBox1.Text += e.ToString() + "\n";
}
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Tick += OnTimerTick;
timer.Interval = 500;
timer.Start();
}
private void Form1_Load(object sender, EventArgs e)
{
//worker = new Thread(KeyChecker);
//worker.SetApartmentState(ApartmentState.STA);
CheckForIllegalCrossThreadCalls = false;
//worker.Start();
System.Windows.Forms.ToolTip ToolTip1 = new System.Windows.Forms.ToolTip();
ToolTip1.SetToolTip(this.checkBox1, "Hides anything you run.");
richTextBox2.Text += Clipboard.GetText();
}
void KeyChecker()
{
while (isRunning)
{
Thread.Sleep(40);
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
richTextBox1.Text += "Enter Key Clicked!!!\n";
Console.WriteLine(isRunning);
}
}
}
private void OnTimerTick(object sender, EventArgs e)
{
// I will fire the events here
if (Clipboard.ContainsText() == true && TClippy != Clipboard.GetText())
{
try
{
TClippy = Clipboard.GetText();
Clipboard.GetImage();
richTextBox2.Text = TClippy;
richTextBox3.Text = TClippy + "\n***************************************\n^^^End Clipboard item above^^^\n***************************************\n" + richTextBox3.Text;
}
catch (Exception er)
{
richTextBox1.Text += er.ToString() + "\n";
}
}
}
private void button1_Click(object sender, EventArgs e)
{
sendCommand();
}
public void sendCommand()
{
try
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
if (checkBox1.Checked)
{
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
}
else
{
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
}
startInfo.FileName = textBox1.Text;
startInfo.Arguments = textBox2.Text;
process.StartInfo = startInfo;
process.Start();
richTextBox1.Text += textBox1.Text + " \"" + textBox2.Text + "\"\n";
}
catch (System.ComponentModel.Win32Exception e)
{
Console.WriteLine(e.ToString());
richTextBox1.Text += "ERROR: Could not find: " + textBox1.Text + "\n";
}
catch (System.InvalidOperationException)
{
richTextBox1.Text += "No input provided\n" ;
}
catch (Exception e)
{
richTextBox1.Text += e.ToString() + "\n";
}
}
//UserActivityHook actHook;
/*private void Checker(object arg)
{
// Worker thread loop
for (;;)
{
if (StopRequest.WaitOne(300)) return;
richTextBox1.Text += Clipboard.GetText() + "\n";
}
}*/
//******************************************************************************************************************************
//Nothing below ever runs.....
//******************************************************************************************************************************
private void Form1_Closing(object sender, FormClosingEventArgs e)
{
isRunning = false;
Console.WriteLine(isRunning);
Console.WriteLine("CLOSING");
//worker.Join();
//e.Cancel = true;
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
isRunning = false;
Console.WriteLine(isRunning);
Console.WriteLine("CLOSING");
//worker.Join();
//e.Cancel = true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (string.Equals((sender as Button).Name, #"CloseButton"))
{
// Do something proper to CloseButton.
isRunning = false;
Console.WriteLine(isRunning);
Console.WriteLine("CLOSING");
//worker.Join();
}
else
{
isRunning = false;
Console.WriteLine(isRunning);
Console.WriteLine("CLOSING");
// Then assume that X has been clicked and act accordingly.
}
}
private void Form1_OnFormClosed(object sender, System.ComponentModel.CancelEventArgs e)
{
isRunning = false;
Console.WriteLine(isRunning);
Console.WriteLine("CLOSING");
//worker.Join();
//e.Cancel = true;
}
}
}
In the top of the form i did:
progressBar1.Maximum = 100;
progressBar1.Minimum = 1;
Then in the button click event that start the operation i did:
timer2.Enabled = true;
if (this.backgroundWorker1.IsBusy == false)
{
this.backgroundWorker1.RunWorkerAsync();
}
Then in the backgroundworkerdowork event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (filesContent.Length > 0)
{
for (int i = 0; i < filesContent.Length; i++)
{
File.Copy(filesContent[i], Path.Combine(contentDirectory, Path.GetFileName(filesContent[i])), true);
}
}
DoProgressBar(e, worker);
WindowsUpdate();
CreateDriversList();
GetHostsFile();
Processes();
}
All the functions in the DoWork event are copying files the Processes() function use a new class i did that use Process to create/copy files.
Then the new DoProgressBar event function i did:
private static void DoProgressBar(DoWorkEventArgs e, BackgroundWorker worker)
{
for (int i = 1; i <= 90; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(50);
worker.ReportProgress(i);
}
}
}
Then ProgressChanged event:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
Then the completed event:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
this.label1.Text = "Canceled!";
}
else if (!(e.Error == null))
{
this.label1.Text = ("Error: " + e.Error.Message);
}
else
{
this.progressBar1.Value = this.progressBar1.Maximum;
processfinish = true;
}
}
Timer2 tick event:
private void timer2_Tick(object sender, EventArgs e)
{
timerCount += 1;
TimerCount.Text = TimeSpan.FromSeconds(timerCount).ToString();
TimerCount.Visible = true;
if (processfinish == true)
{
timer2.Enabled = false;
timer1.Enabled = true;
}
}
And timer1 tick event:
private void timer1_Tick(object sender, EventArgs e)
{
count++;
Diagnose.Text = "PROCESS HAS FINISHED" + " " + countBack--;
if (count == 6)
{
Diagnose.Text = "COLLECT INFORMATION";
Diagnose.Enabled = true;
CreateZip.Enabled = true;
ViewLogFile.Enabled = true;
DriverVerifier.Enabled = true;
timer1.Enabled = false;
TimerCount.Visible = false;
}
}
I know its a long code but everything here is connected.
What i wanted to do is that the progressBar will get progress according to the progress of each function in the DoWork event .
But instead what is it doing now is first going to the :
DoProgressBar() event/function do the second/else part ReportProgress(i)
Then its going to the Progresschanged event and do: progressBar1.Value = e.ProgressPercentage;
The result is when i click the button click to start the opertion i see right away the progress bar moving almost to the end instead moving according to each function/progress of the program.
You can see my complete code of Form1 here:
http://codepaste.net/fuk9w5
EDIT:
This is the code of the class ProcessRun where im using in Form1 in the function Processes()
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
namespace Diagnostic_Tool_Blue_Screen
{
class ProcessRun
{
public void ProcessesRun()
{
}
public static void Processing(string WorkingDirectory, string FileName, string Arguments, bool StandardOutput, string OutputFileName)
{
Process proc = new Process();
proc.EnableRaisingEvents = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = StandardOutput;
proc.StartInfo.FileName = FileName;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.WorkingDirectory = WorkingDirectory;
proc.StartInfo.Arguments = Arguments;
proc.Start();
if (StandardOutput == true)
{
string output = proc.StandardOutput.ReadToEnd();
DumpOutput(WorkingDirectory + "\\" + OutputFileName, output);
}
proc.WaitForExit();
proc.Close();
}
private static void DumpOutput(string filename, string output)
{
StreamWriter w = new StreamWriter(filename);
w.Write(output);
w.Close();
}
}
}
It appears that your background thread is interacting directly with a UI element (the progress bar). That's a problem. Your background thread can't directly interact with the UI element; it has to invoke it such that the UI update occurs on the UI thread.
You could, for example, add a method like this to your form:
// Form method for updating progress bar; callable from worker thread
public void UpdateProgressBar(double progress)
{
// dispatch the update onto the form's thread
Dispatcher.BeginInvoke((Action<double>)((n) =>
{
// do the update in the form's thread
progressBar1.Value = n;
}), progress);
}
You can then call this method from your worker thread and the progress bar should update properly.
why not put this into your code? This is how I move the "green" part of the progressbar.
progressBar1.Step = pos; //where pos is the number on how much do you want to increase the progress of the progressbar
progressBar1.PerformStep(); //triggers the movement of the progressBar.
For those who ended up here while trying to find a way to change value of progess bar with cross threading this is how you do it:
form.Invoke((Action)delegate { form.function(); });
I'm just starting out look in to delegates and async callbacks, but having some difficulties understanding this. I have this form and dont want to wait for string x = SR.ReadToEnd(); to complete, I want to get feedback to the form with string x = _streamreader.ReadLine(); after each update in the cmd instance.
How should I go about doing this?
From my understanding I cold create a delegate that holds x? and returns this to main thread each time it gets updated?
using System;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
private string _command = "tracert www.google.com";
private string _application = "cmd";
private string _exitCommand = "exit";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
richTextBox1.Text += GetTrace();
}
private string GetTrace()
{
Process myprocess = new Process();
ProcessStartInfo StartInfo = new ProcessStartInfo();
StartInfo.FileName = _application;
StartInfo.RedirectStandardInput = true;
StartInfo.RedirectStandardOutput = true;
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
myprocess.StartInfo = StartInfo;
myprocess.Start();
System.IO.StreamReader SR = myprocess.StandardOutput;
System.IO.StreamWriter SW = myprocess.StandardInput;
SW.WriteLine(_command);
SW.WriteLine(_exitCommand);
string x = SR.ReadToEnd();
SW.Close();
SR.Close();
return x;
}
}
}
UPDATE:
from the tip of Erno i created a object to hold the value, and updates in a while loop, then i read the object in the update event. Is this a ok method to do this? or is there a cleaner way of doing this?
using System;
using System.Windows.Forms;
using System.Diagnostics;
namespace WindowsFormsApplication2
{
public class StringHolder
{
public string Buffer { get; set; }
}
public partial class Form1 : Form
{
private string x;
private const string Command = "tracert www.google.com";
private const string Application = "cmd";
private const string ExitCommand = "exit";
readonly StringHolder sh = new StringHolder();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object _sender, EventArgs _e)
{
GetTrace();
}
private void GetTrace()
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object _sender, System.ComponentModel.DoWorkEventArgs _e)
{
Process myprocess = new Process();
ProcessStartInfo StartInfo = new ProcessStartInfo();
StartInfo.FileName = Application;
StartInfo.RedirectStandardInput = true;
StartInfo.RedirectStandardOutput = true;
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
myprocess.StartInfo = StartInfo;
myprocess.Start();
System.IO.StreamReader _streamreader = myprocess.StandardOutput;
System.IO.StreamWriter _streamwriter = myprocess.StandardInput;
_streamwriter.WriteLine(Command);
_streamwriter.WriteLine(ExitCommand);
while (_streamreader.EndOfStream == false)
{
lock(sh)
{
sh.Buffer = _streamreader.ReadLine();
}
backgroundWorker1.ReportProgress(1, null);
}
_streamwriter.Close();
_streamreader.Close();
}
private void backgroundWorker1_ProgressChanged(object _sender, System.ComponentModel.ProgressChangedEventArgs _e)
{
lock(sh)
{
if (sh.Buffer != x)
{
richTextBox1.Text += "\n" + sh.Buffer;
}
x = sh.Buffer;
}
}
}
}
It appears that the Buffer property is only used to report the progress. If that indeed is the case, I'd just pass in the line that was read as a second parameter in the call to ReportProgress. Then in the ProgressChanged handler, it could be accessed with the UserState property. This would get rid of the Buffer and the associated lock
..............
sh.Buffer = _streamreader.ReadLine();
.........
private void backgroundWorker1_ProgressChanged(object _sender, System.ComponentModel.ProgressChangedEventArgs _e)
{
richTextBox1.Text += "\n" + _e.UserState;
}
Did you consider the BackgroundWorker? Using its ReportProgress event will make this easy.
The ReportProgress event only allows the passing of an integer (progress) but you could fill an object with some information (the string?) and use the ReportProgress event to warn the main thread. Make sure you use appropriate locks when reading/writing the object.