Im trying to create a minecraft server wrapper but im having trouble reading the output of the process. I want to read the output in the serverProcess_ErrorDataRecevied event and I know that what there is now doesn't work. But what could I put there instead to read it?
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;
using System.Diagnostics;
using System.IO;
namespace MC_Server_UI
{
public partial class Form1 : Form
{
ProcessStartInfo startInfo = new ProcessStartInfo("C:\\Program Files (x86)\\Java\\jre7\\bin\\java.exe", "Xmx1024M - jar " + "craftbukkit.jar" + " nogui");
Process serverProcess;
OpenFileDialog ofd;
FolderBrowserDialog fbd;
public Form1()
{
InitializeComponent();
fbd = new FolderBrowserDialog();
fbd.ShowDialog();
startInfo.WorkingDirectory = fbd.SelectedPath;
startInfo.RedirectStandardInput = startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
serverProcess = new Process();
serverProcess.StartInfo = startInfo;
serverProcess.EnableRaisingEvents = true;
serverProcess.ErrorDataReceived += new DataReceivedEventHandler(serverProcess_ErrorDataReceived);
serverProcess.Exited += new EventHandler(serverProcess_Exited);
serverProcess.Start();
}
private void serverProcess_ErrorDataReceived(object sender, EventArgs e)
{
richTextBox1.AppendText(serverProcess.StandardError.ReadToEnd());
}
private void serverProcess_Exited(object sender, EventArgs e)
{
}
}
}
See:
How to spawn a process and capture its STDOUT in .NET?
ProcessStartInfo.RedirectStandardOutput
Code:
serverProcess.StartInfo.RedirectStandardOutput = true;
serverProcess.OutputDataReceived += (sender, args) => Console.WriteLine("received output: {0}", args.Data);
serverProcess.Start();
serverProcess.BeginOutputReadLine();
Or:
serverProcess.StartInfo.RedirectStandardOutput = true;
var output = serverProcess.StandardOutput.ReadToEnd();
See also: ProcessStartInfo.RedirectStandardError
serverProcess.StartInfo.RedirectStandardError = true;
var error = serverProcess.StandardError.ReadToEnd();
Related
I'm using this code :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace System_Information
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
GetInfo();
}
private void GetInfo()
{
Process process = new Process();
process.EnableRaisingEvents = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "msinfo32.exe";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.Arguments = "/report D:\\Info\\report.txt";
process.StartInfo.WorkingDirectory = "D:\\Info";
process.Start();
process.WaitForExit();
process.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
but it's creating a very big file size 1.5MB of information.
if I want to use the msinfo32 but to show for example only the memory , video car , and mother board info? How can I select it to show only this info ?
I have a little problem with my code, I would like to use two variables string numberTextBox1 and numberTextBox2 in a static void function to replace the variables chiffre_1 and chiffre_2
I looked at converting string to var ==> failure
I tried to set the variables numberTextBox 1 and 2 ==> as a function argument
I tried to set function variables equal to TextBox1.Text and TextBox2.Text ==> failed
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using IronPython;
using IronPython.Hosting;
using System.IO;
namespace CSharp_with_Python_Script
{
public partial class Form1 : Form
{
string nombreTextbox1;
string nombreTextbox2;
string chiffre_1;
string chiffre_2;
public Form1()
{
InitializeComponent();
}
static void Execute(nombreTextBox1,
nombreTextBox2)
{
var psi = new ProcessStartInfo();
psi.FileName =
#"C:\Users\adm\AppData\Local\Programs\Python\Python37-32\python.exe";
var script = #"C:\Users\adm\Documents\Visual Studio
2017\Projects\CSharp_with_Python_Script\Class_Plot\Class_Plot.py";
var chiffre_1 = nombreTextBox1;
var chiffre_2 = nombreTextBox2;
psi.Arguments = $"\"{script}\" \"{chiffre_1}\" \"{chiffre_2}\"";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var errors = "";
var result = "";
using (var process = Process.Start(psi))
{
errors = process.StandardError.ReadToEnd();
result = process.StandardOutput.ReadToEnd();
}
}
private void Btn_ChangePicture_Click(object sender, EventArgs e)
{
pictureBox1.ImageLocation = (#"C:\Users\adm\Documents\Visual
Studio
2017\Projects\CSharp_with_Python_Script\Class_Plot\PLOT_MATPLOTLIB.png");
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
}
private void Btn_Script_Click(object sender, EventArgs e)
{
Execute();
}
private void button1_Click(object sender, EventArgs e)
{
nombreTextbox1 = textBox1.Text;
nombreTextbox2 = textBox2.Text;
}
}
}
I would like the variables chiffre_1 and chiffre_2 of the function to be equal to the variables entered in the function Execute
Ps: I am a beginner in C # and novice in the functions
try that
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using IronPython;
using IronPython.Hosting;
using System.IO;
namespace CSharp_with_Python_Script
{
public partial class Form1 : Form
{
string nombreTextbox1;
string nombreTextbox2;
string chiffre_1;
string chiffre_2;
public Form1()
{
InitializeComponent();
}
static void Execute()
{
chiffre_1 = nombreTextBox1;
chiffre_2 = nombreTextBox2;
var psi = new ProcessStartInfo();
psi.FileName =
#"C:\Users\adm\AppData\Local\Programs\Python\Python37-32\python.exe";
var script = #"C:\Users\adm\Documents\Visual Studio
2017\Projects\CSharp_with_Python_Script\Class_Plot\Class_Plot.py";
var chiffre_1 = nombreTextBox1;
var chiffre_2 = nombreTextBox2;
psi.Arguments = $"\"{script}\" \"{chiffre_1}\" \"{chiffre_2}\"";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var errors = "";
var result = "";
using (var process = Process.Start(psi))
{
errors = process.StandardError.ReadToEnd();
result = process.StandardOutput.ReadToEnd();
}
}
private void Btn_ChangePicture_Click(object sender, EventArgs e)
{
pictureBox1.ImageLocation = (#"C:\Users\adm\Documents\Visual
Studio
2017\Projects\CSharp_with_Python_Script\Class_Plot\PLOT_MATPLOTLIB.png");
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
}
private void Btn_Script_Click(object sender, EventArgs e)
{
Execute();
}
private void button1_Click(object sender, EventArgs e)
{
nombreTextbox1 = textBox1.Text;
nombreTextbox2 = textBox2.Text;
}
}
}
When throw event button1_Click it's set nombreTextbox1 and nombreTextbox2 after that Btn_Script_Click launch Execute() method and use a private property to set chiffre_1 and chiffre_2 with a new value.
I have little problem with stopping infinite Pinging.
If you see in picture I ping IP 127.0.0.1 it has infinite ping ( -t ).
And I want do that when I Click Stop! button then it stops pinging.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Diagnostics;
using System.Net;
using System.Management;
namespace PingProgramm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread th;
private void button1_Click(object sender, EventArgs e)
{
th = new Thread(thread1);
th.Start();
}
public void thread1()
{
try
{
string command = "/c ping -t " + textBox1.Text;
ProcessStartInfo procStartInfo = new ProcessStartInfo("CMD", command);
Process proc = new Process();
proc.StartInfo = procStartInfo;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardInput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
catch (Exception)
{
//if an error occurs with in the try block, it will handled here.
}
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
string newLine = e.Data.Trim() + Environment.NewLine;
MethodInvoker append = () => richTextBox1.Text += newLine;
richTextBox1.BeginInvoke(append);
}
}
bool firstTime = true;
private void textBox1_Click(object sender, EventArgs e)
{
if (firstTime)
{
firstTime = false;
textBox1.Clear();
}
}
private void button2_Click(object sender, EventArgs e)
{
}
}
}
Best wishes
KLDesigns,
The simplest thing that might work in your current code is to get hold of your Process instance in the DataReceived event and cancel the process there (or send a Ctrl+C on the stdin).
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (stop)
{
// sender is our process instance
// so we can cast that safely here
var proc = (Process) sender;
// brutally kill it
proc.Kill();
// or more gently, send a ctrl+C
// http://stackoverflow.com/a/285041/578411
proc.StandardInput.Close();
}
if (e.Data != null)
{
string newLine = e.Data.Trim() + Environment.NewLine;
MethodInvoker append = () => richTextBox1.Text += newLine;
richTextBox1.BeginInvoke(append);
}
}
You can set the boolean stop in your click event handler:
bool stop = false;
private void button2_Click(object sender, EventArgs e)
{
stop = true;
}
Keep in mind that if you want to keep control over object instances you create consider keeping a reference to them. As you create the Process inside the thread your form can't reach it any more. If you would have made the proc an member of your form you could have called proc.StandardInput.Close() from your click event.
This question already has answers here:
How to read to end process output asynchronously in C#?
(4 answers)
Closed 8 years ago.
I have a textbox and a button. The button invokes Ping() and I want any progress of ping to be displayed in textBox1.
void Ping()
{
p = new Process();
p.StartInfo.FileName = "ping";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.Arguments = "www.microsoft.com";
p.Start();
textBox1.Text = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
How to achieve it? The current implementation I wrote above does not show the progress but the final output.
async void Test()
{
await Ping("www.google.com");
}
Task Ping(string host)
{
var tcs = new TaskCompletionSource<object>();
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "ping.exe";
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.Arguments = host;
var proc = Process.Start(psi);
proc.OutputDataReceived += (s, e) => {
Action action = () => textBox1.Text += e.Data + Environment.NewLine;
this.Invoke(action);
};
proc.Exited += (s, e) => tcs.SetResult(null);
proc.EnableRaisingEvents = true;
proc.BeginOutputReadLine();
return tcs.Task;
}
RESULT
Pinging www.google.com [64.15.117.154] with 32 bytes of data:
Reply from 64.15.117.154: bytes=32 time=50ms TTL=55
Reply from 64.15.117.154: bytes=32 time=45ms TTL=55
Reply from 64.15.117.154: bytes=32 time=45ms TTL=55
Reply from 64.15.117.154: bytes=32 time=46ms TTL=55
Ping statistics for 64.15.117.154:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 45ms, Maximum = 50ms, Average = 46ms
Having said that, I would use the Ping class instead of launching an external application
var ping = new System.Net.NetworkInformation.Ping();
var pingReply = await ping.SendPingAsync("www.google.com");
Console.WriteLine("{0} {1} {2}",pingReply.Address,
pingReply.RoundtripTime,
pingReply.Status);
Update
After receiving QtX comment, I went ahead and re-did the entire project in WinForms.
Here's the updated code and a screenshot, hope this helps you.
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;
using System.Diagnostics;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Process p;
public Form1()
{
InitializeComponent();
}
private void cmdPing_Click(object sender, EventArgs e)
{
p = new Process();
startNewThread();
}
public void Log(string line)
{
txtOutput.Text += line + System.Environment.NewLine;
}
private void startNewThread()
{
Thread x = new Thread(new ThreadStart(Ping));
x.IsBackground = true;
x.Start();
}
private void Ping()
{
p.StartInfo.FileName = "ping.exe";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.Arguments = txtAddress.Text;
p.Start();
while (p.StandardOutput.Peek() > -1)
{
this.Invoke((MethodInvoker)delegate() { Log(p.StandardOutput.ReadLine()); });
p.StandardOutput.DiscardBufferedData();
}
}
}
}
Screenshot of Form
I have worked on this issue for a while. I can capture the output(live) of the console window just fine, but I can't capture the output of a python console application in real time. I can capture the output of the python program after it has finished running, but i don't want that.
I am using process from system.diagonistics. with a background worker.
I simply want to capture the python26 output onto a text box. I have tested my program with other custom applications, and it does display the output(live).
Help please
Thanks
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;
using System.Diagnostics;
using System.Threading;
using System.IO;
namespace ProcessDisplayoutput
{
public partial class Form1 : Form
{
//Delegates
delegate void AppendTextDelegate(string text);
public Form1()
{
InitializeComponent();
Worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
}
private void StartButton_Click(object sender, EventArgs e)
{
ResultTextBox.Clear();
if (!Worker.IsBusy)
{
Worker.RunWorkerAsync();
}
}
public void Worker_DoWork(object sender, DoWorkEventArgs e)
{
Process pro = new Process();
pro.StartInfo.RedirectStandardOutput = true;
pro.StartInfo.RedirectStandardError = true;
pro.StartInfo.UseShellExecute = false;
pro.StartInfo.CreateNoWindow = true;
pro.EnableRaisingEvents = true;
pro.OutputDataReceived +=new DataReceivedEventHandler(OnDataReceived);
pro.ErrorDataReceived +=new DataReceivedEventHandler(OnDataReceived);
//Test with random program worked,
//now need to test with python
//*****************TEST 1: PASSED **************************
pro.StartInfo.FileName = "C:\\TestProcessOutput.exe";
//*****************END TEST1*******************************
//*****************TEST 2: FAILED *************************
//pro.StartInfo.FileName = "C:\\Python26\\python.exe";
//pro.StartInfo.Arguments = "\"C:\\Python26\\testScript.py\"";
//*****************END TEST2 *******************************
StreamReader sr = null;
try
{
pro.Start();
pro.BeginOutputReadLine();
//An alternative option to display the output with the same results
//sr = pro.StandardOutput;
//string line = "";
//while ((line = sr.ReadLine()) != null)
//{
// appendText(line);
// }
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public void OnDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
string temp = (e.Data) + Environment.NewLine;
appendText(temp);
}
}
public void appendText(string text)
{
if (ResultTextBox.InvokeRequired)
{
ResultTextBox.Invoke(new AppendTextDelegate(appendText), new object[] { text });
}
else
{
ResultTextBox.AppendText(text);
}
}
I just ran into this question myself, and after a ton of experimenting, what worked for me was running the python process with the "-u" option, which makes the output unbuffered. With that, everything worked completely fine.
I ran into this problem while making a MiniConsole exactly for that purpose.
I used your technique with
pro.EnableRaisingEvents = true;
pro.OutputDataReceived +=new DataReceivedEventHandler(OnDataReceived);
pro.ErrorDataReceived +=new DataReceivedEventHandler(OnDataReceived);
The strange thing is that all the output was coming from ErrorDataReceived instead of OutputDataReceived (with valid commands).
So I think you're missing:
pro.BeginErrorReadLine();
Also I was starting the process in the main thread (I don't have any worker), using python27.
Here is the full start:
// executable: "c:\\python27\\python.exe", arguments: "myscript.py"
ProcessStartInfo startInfo = new ProcessStartInfo(executable, arguments);
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.WorkingDirectory = textBoxWorkingDirectory.Text;
try
{
Process p = new Process();
p.StartInfo = startInfo;
p.EnableRaisingEvents = true;
p.OutputDataReceived += new DataReceivedEventHandler(OnDataReceived);
p.ErrorDataReceived += new DataReceivedEventHandler(OnDataReceived);
p.Exited += new EventHandler(OnProcessExit);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
}
I remember having a similar issue a while back and I think I did something similar to this in my .py scripts instead of using the print function:
sLog = 'Hello World!'
subprocess.Popen( 'echo ' + sLog, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )
Not sure if I set the shell parameter to True or False though. Also not sure about all the "std" parameters. You might want to experiment a bit there.
If you're starting the Python process from your code, then THIS will make your life really easy and I think it's about the cleanest way to go.