Receiving status updates from cmd application - c#

I am using some microscopy software which can be remotely controlled using a small command line based application. To use this application more efficiently I would like to write my own piece of software for that using C#.
I already managed to connect to the main software using this:
public partial class Form1 : Form
{
Process receiver = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "WSxMrc.exe",
Arguments = "-m recv -a 127.0.0.1 -p 9602",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
private void button1_Click(object sender, EventArgs e)
{
bConnect.Enabled = false;
bDconnect.Enabled = true;
receiver.Start();
}...
Using the application in the cmd, it receives now information whenever an image was acquired and so on. I would like to use these received statuses to act on whatever happened. For example, change the scan area after an image was captured.
I'm pretty sure I have to raise some sort of event to record the incoming status and that's where I'm stuck now. I have no idea how to create an event which recognizes whenever a new message is send to the receiver process.

You need to use the OutputDataRecieved event to handle the redirected output.
Add these lines after reciever.Start()
receiver.OutputDataReceived += receiver_OutputDataReceived;
receiver.BeginOutputReadLine();
and then add the event handler
void reciever_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
...
}
More information can be found here
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.outputdatareceived.aspx

Related

Basic use of Linklabel tool in winforms gives Exception Handling Error [duplicate]

I recently started to work with dynamic components, and it worked fine until I started with dynamic linked label. So here's my Problem: I want to open a website through a label link but every time I try to do that, it happens to break the program and give me the error: System.ComponentModel.Win32Exception.
private void CreateDynamicLinkedLabel() {
LinkLabel mylinklab = new LinkLabel();
mylinklab.Text = "asdasdasda";
mylinklab.AutoSize = true;
mylinklab.LinkClicked += new LinkLabelLinkClickedEventHandler(mylinklab_Clicked);
Controls.Add(mylinklab);
}
private void mylinklab_Clicked(object sender, LinkLabelLinkClickedEventArgs e) {
Process.Start("http://www.google.com");
}
I also tried this:
private void mylinklab_Clicked(object sender, LinkLabelLinkClickedEventArgs e) {
Process.Start("chrome.exe","http://www.google.com");
}
i even included using System.Diagnostics;
I tried to figure out why it wont work, but every Youtube Video looks like my code.
Maybe there is another way to open a link, but i cant figure it out.
I assume that you are targeting net core 3+. In this case you need to explicitly set UseShellExecute=true to get behaviour as it was in net framework. In net core there was a breaking changes in the default options for new process. More details https://github.com/dotnet/runtime/issues/17938
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
};
Process.Start (psi);
Add this in your method in your code:
Process.Start(new ProcessStartInfo() { FileName = url, UseShellExecute = true });

Dynamic Linked Label cannot open a website

I recently started to work with dynamic components, and it worked fine until I started with dynamic linked label. So here's my Problem: I want to open a website through a label link but every time I try to do that, it happens to break the program and give me the error: System.ComponentModel.Win32Exception.
private void CreateDynamicLinkedLabel() {
LinkLabel mylinklab = new LinkLabel();
mylinklab.Text = "asdasdasda";
mylinklab.AutoSize = true;
mylinklab.LinkClicked += new LinkLabelLinkClickedEventHandler(mylinklab_Clicked);
Controls.Add(mylinklab);
}
private void mylinklab_Clicked(object sender, LinkLabelLinkClickedEventArgs e) {
Process.Start("http://www.google.com");
}
I also tried this:
private void mylinklab_Clicked(object sender, LinkLabelLinkClickedEventArgs e) {
Process.Start("chrome.exe","http://www.google.com");
}
i even included using System.Diagnostics;
I tried to figure out why it wont work, but every Youtube Video looks like my code.
Maybe there is another way to open a link, but i cant figure it out.
I assume that you are targeting net core 3+. In this case you need to explicitly set UseShellExecute=true to get behaviour as it was in net framework. In net core there was a breaking changes in the default options for new process. More details https://github.com/dotnet/runtime/issues/17938
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
};
Process.Start (psi);
Add this in your method in your code:
Process.Start(new ProcessStartInfo() { FileName = url, UseShellExecute = true });

Disable C# Form until external Excel application is closed

I have a button on a C# Windows forms application that runs the code below:
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
string path = "D:\MyCsvFile.csv";
Process.Start(path);
}
Basically, the user needs to be able to make changes to a CSV file. The user is most comfortable making these changes in Microsoft Excel. I found the above code online from someone who has many years of experience working with MS Office products and C#. This guy explained that the code below works but is more error prone than using "Process.Start()" as shown above.
string path = "D:\MyCsvFile.csv";
var ExcelApp = new Excel.Application();
ExcelApp.Workbooks.OpenText(path, Comma: true);
ExcelApp.Visible = true;
This guy explains that "Process.Start()" works because Windows is set up to use Excel as the default program for opening CSV files.
Anyways, when the user clicks the button above (btnAddDataToCSV), I need my C# form to become disabled (all the buttons grayed out) until the user closes the Excel workbook that is displaying the CSV file. Potentially, I may need the C# program to read the CSV file immediately after the user closes Excel.
Ho do I do this?
I assume... I need to do something like... "disable C# form... then Wait for Excel close event... then once excel close event happens... enable C# form and read CSV file."
Below is the code I have for reading the CSV file:
string path = "D:\MyCsvFile.csv";
var reader = new StreamReader(File.OpenRead(path));
List<string> listA = new List<string>();
List<string> listB = new List<string>();
List<string> listC = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
listA.Add(values[0]);
listB.Add(values[1]);
listC.Add(values[2]);
}
I think that you need to use an event handler for process that exits.
Something like this:
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
//disable form
string path = "D:\MyCsvFile.csv";
using (myProcess = new Process())
{
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(Excel_Exit);
myProcess.Start(path);
}
}
public void Excel_Exit(object sender, System.EventArgs e){
//enableForm
}
Process.Exited example in documentation: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.exited?view=netcore-3.1
I was unable to get the solution above to work even though the solution is similar to Microsoft's solution.
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.exited?view=netcore-3.1
I found this:
Why is my process's Exited method not being called?
It says:
"I've come across examples that place new Process() in a using clause. Do not do that if you want to use the Exited feature. The using clause destroys the instance along with any event handles on Exited."
It says:
using(var process = new Process())
Should be:
var process = new Process();
This makes no since because the link above that I provided for Microsoft is an example of how to use the "Process.Exited Event" and it uses "using(var process = new Process())"
But sure enough... for some reason when I tried "var process = new Process();" it worked... This is the code that worked:
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
var myProcess = new Process();
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(Excel_Exit);
myProcess.StartInfo.FileName = "D:\\MyCsvFile.csv";
myProcess.Start();
}
public void Excel_Exit(object sender, System.EventArgs e)
{
MessageBox.Show("Success!!");
}
Here is the code that does not work... But I don't understand why because it is similar to Microsoft's example.
private Process myProcess;
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
using (myProcess = new Process())
{
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(Excel_Exit);
myProcess.StartInfo.FileName = "D:\\MyCsvFile.csv";
myProcess.Start();
}
}
public void Excel_Exit(object sender, System.EventArgs e)
{
MessageBox.Show("Success!!");
}
When you close excel... the event never fires... Can someone explain this? Surely Microsoft's example isn't wrong.

Console within form Visual C#

I want to get a console window within my form. Basically when you click button1, it runs a batch script(test.exe). I don't want a separate batch window but instead I want it to show up within my form.
I figure there are probably two ways of doing this, either 1, somehow embedding the console within my form, or 2, set StartInfo.CreateNoWindow = true; when you click button1 and get the output to funnel into a listbox to simulate a console within my form.
I am just a little stuck because I have found methods for doing both but my own testing with the various other methods people have suggested, nothing has worked. But either way, my user needs to be able to send input back to the console.
Which method would be simpler and how would I go about it?
I believe the best way to do this is to redirect output. Basically things will still execute as you want, but you will get the output wherever you want/need.
using System;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
namespace ConsoleOutput_test
{
public partial class Form1 : Form
{
Process sortProcess;
private static StringBuilder sortOutput = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
sortProcess = new Process();
sortProcess.StartInfo.FileName = "C:\\Windows\\System32\\cmd.exe";
// Set UseShellExecute to false for redirection.
sortProcess.StartInfo.CreateNoWindow = true;
sortProcess.StartInfo.UseShellExecute = false;
// Redirect the standard output of the sort command.
// This stream is read asynchronously using an event handler.
sortProcess.StartInfo.RedirectStandardOutput = true;
sortProcess.StartInfo.RedirectStandardInput = true;
sortProcess.StartInfo.RedirectStandardError = true;
sortOutput = new StringBuilder("");
// Set our event handler to asynchronously read the sort output.
sortProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
sortProcess.ErrorDataReceived += new DataReceivedEventHandler(SortErrorHandler);
// Redirect standard input as well. This stream
// is used synchronously.
sortProcess.StartInfo.RedirectStandardInput = true;
// Start the process.
sortProcess.Start();
// Start the asynchronous read of the sort output stream.
sortProcess.BeginOutputReadLine();
while (!sortProcess.HasExited)
{
Application.DoEvents(); // This keeps your form responsive by processing events
}
}
private void SortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (txtConsole.InvokeRequired) { txtConsole.BeginInvoke(new DataReceivedEventHandler(SortOutputHandler), new[] { sendingProcess, outLine }); }
else
{
txtConsole.AppendText(Environment.NewLine + outLine.Data);
}
}
private void SortErrorHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (txtConsole.InvokeRequired) { txtConsole.BeginInvoke(new DataReceivedEventHandler(SortErrorHandler), new[] { sendingProcess, outLine }); }
else
{
txtConsole.AppendText(Environment.NewLine + outLine.Data);
}
}
private void button2_Click(object sender, EventArgs e)
{
sortProcess.StandardInput.WriteLine(txtOutput.Text);
txtOutput.Text = "";
}
}
}

Redirect Python standard input/output to C# forms application

I apologize if this is a duplicate question, I searched a bit and couldn't find anything similar - I have a Python library that connects to my C# application via a socket in order to allow simple Python scripting (IronPython isn't an option right now for a couple of reasons). I would like to create a Windows Forms control that would be basically a graphical front-end for the Python interpreter, so that the user could run the interpreter without having to have a separate console window open.
I attached a simple demo of what I've tried so far below, but I haven't been able to get it to work. The DataReceived event handlers are never called, and when I try to write to the standard input nothing happens in the interpreter. Does anyone have any feedback about what I'm doing wrong, or if this is even possible?
public partial class Form1 : Form
{
Process _pythonProc;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ProcessStartInfo psi = new ProcessStartInfo()
{
FileName = #"C:\Python26\Python.exe",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
_pythonProc = new Process();
_pythonProc.OutputDataReceived += OutputDataReceived;
_pythonProc.ErrorDataReceived += ErrorDataReceived;
_pythonProc.StartInfo = psi;
_pythonProc.Start();
}
private void cmdExecute_Click(object sender, EventArgs e)
{
string cmd = textInput.Text;
_pythonProc.StandardInput.WriteLine(cmd);
_pythonProc.StandardInput.Flush();
textInput.Text = string.Empty;
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (!_pythonProc.HasExited)
_pythonProc.Kill();
}
private void OutputDataReceived(object sender, DataReceivedEventArgs args)
{
textOutput.Text += args.Data;
}
private void ErrorDataReceived(object sender, DataReceivedEventArgs args)
{
textOutput.Text += args.Data;
}
}
In case anyone else stumbles across this, I figured out the problem - by default, the Python interpreter only enters interactive mode if it detects that a TTY device is connected to standard input (which is normally only true if the program is run from the console). In order to redirect the standard IO streams, you have to set UseShellExecute in the ProcessStartInfo to false, which causes the interpreter to think that there is no TTY connected, meaning it immediately exits since it has nothing to do.
The solution is to run the Python interpreter with the "-i" command line argument, which forces the interpreter to interactive mode, regardless of whether there is a TTY connected to standard in. This makes the example above work correctly.
write in separate thread:
while(cond)
{
string s = _pythonProc.StandardOutput.ReadLine();
textOutput.Invoke( () => { textOutput.Text += s; } );
}

Categories

Resources