command prompt commands executing in windows application - c#

i am trying in windows application i need to run another one application that's tetpdflib. that tetpdflib runs in command prompt only. when i drag and drop exe to the command prompt it will execute. for that i followed some coding
Process tetmlProcess = new Process();
tetmlProcess.StartInfo.CreateNoWindow = true;
tetmlProcess.StartInfo.RedirectStandardOutput = true;
tetmlProcess.StartInfo.UseShellExecute = false;
tetmlProcess.StartInfo.FileName = #"cmd.exe";
tetmlProcess.StartInfo.Arguments = "cd C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin\\tet.exe";
tetmlProcess.Start();
but i cant get output.. and also i need to run following command prompt lines also
cd tet.exe
and tet -m filename
how to execute those commands in that process.
thats the full coding
public static string inputfile = string.Empty;
public static string outputfolder = string.Empty;
private void btninputbrowse_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog inputFileBrowser = new OpenFileDialog();
DialogResult result = inputFileBrowser.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
inputfile = inputFileBrowser.FileName;
txtinput.Text = inputFileBrowser.FileName;
}
}
private void btnoutputbrowse_Click(object sender, RoutedEventArgs e)
{
FolderBrowserDialog folderbrowsing = new FolderBrowserDialog();
DialogResult result = folderbrowsing.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
outputfolder = folderbrowsing.SelectedPath;
txtoutput.Text = folderbrowsing.SelectedPath;
}
}
private void btnok_Click(object sender, RoutedEventArgs e)
{
MoveInputFileToOutPutFolder();
}
private void MoveInputFileToOutPutFolder()
{
try
{
string[] splitinput = inputfile.Split('\\');
outputfolder = System.IO.Path.Combine(outputfolder,splitinput.LastOrDefault());
if (File.Exists(outputfolder))
{
File.Delete(outputfolder);
}
File.Copy(inputfile,outputfolder);
TetmlApplicationRunning();
}
catch (Exception)
{
throw;
}
}
private void TetmlApplicationRunning()
{
try
{
Process tetmlProcess = new Process();
//tetmlProcess.StartInfo.CreateNoWindow = true;
//tetmlProcess.StartInfo.RedirectStandardOutput = true;
//tetmlProcess.StartInfo.UseShellExecute = false;
tetmlProcess.StartInfo.FileName = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin\\tet.exe";
tetmlProcess.StartInfo.WorkingDirectory = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin";
tetmlProcess.StartInfo.Arguments = "tetml -m wordplus" + inputfile;
tetmlProcess.Start();
}
catch (Exception)
{
throw;
}
}
}
}

You can do it like below. you won't need to run cmd.exe you can directly run tet.ext. Added comments in code.
Process tetmlProcess = new Process();
tetmlProcess.StartInfo.CreateNoWindow = true;
tetmlProcess.StartInfo.RedirectStandardOutput = true;
tetmlProcess.StartInfo.UseShellExecute = false;
// Instead of cmd.exe you run the tet.exe
tetmlProcess.StartInfo.FileName = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin\\tet.exe";
//Set The working directory to C:\Users\sw_chn\Documents\PDFlib\TET 5.0 32-bit\bin\ if needed
tetmlProcess.StartInfo.WorkingDirectory = #"C:\\Users\\sw_chn\\Documents\\PDFlib\\TET 5.0 32-bit\\bin";
//Use the arguments required for tet.exe
tetmlProcess.StartInfo.Arguments = "-m filename";
tetmlProcess.Start();
Note: This code is directly typed in here (have no access to visual studio now) so may contain syntax errors. Treat this only as guideline.

try the following snippet:
var proc = new ProcessStartInfo();
string yourCommand;
yourCommand = "calc.exe";
proc.UseShellExecute = true;
proc.WorkingDirectory = #"C:\Windows\System32";
proc.FileName = #"C:\Windows\System32\cmd.exe";
proc.Arguments = "/c " + yourCommand;
proc.WindowStyle = ProcessWindowStyle.Normal;
Process.Start(proc);
I run calculator; you can run your program as tet.exe and you must set the other parameters such as WorkingDirectory and FileName based on your .exe file.
This line of code
proc.WindowStyle = ProcessWindowStyle.Normal;
displays the cmd.exe window. If you are gonna not to display that, change the mentioned line of code to proc.WindowStyle = ProcessWindowStyle.Hidden;
I hope that work out!

I owuld not try to simulate the command prompt, but execute the application directly. I assume that for this application output is sent to the console. You can redirect this output, but it is not possible to combine this with shell execute. I use the full path name to the application, which I set in the "Options" class and is stored in the registry. An example:
static public String CompileScript(String InputFile, String OutputFile)
{
Process Compiler = new Process();
String Result = String.Empty;
try
{
Compiler.StartInfo.FileName = CLuaCreatorOptions.TrainSimulatorDirectory + "\\luac.exe";
Compiler.StartInfo.Arguments = "-v -o " + OutputFile + " " + InputFile;
Compiler.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Compiler.StartInfo.CreateNoWindow = true;
Compiler.StartInfo.UseShellExecute = false;
Compiler.StartInfo.RedirectStandardOutput = true;
Compiler.StartInfo.RedirectStandardError = true;
Compiler.Start();
Result = Compiler.StandardOutput.ReadToEnd() + "\n" + Compiler.StandardError.ReadToEnd();
Compiler.WaitForExit();
}
catch (Exception e)
{
return "Error compiling script " + e.Message + "\r\n" + Result;
}
return Result;
}
This example runs the LUA compiler and returns all error messages (async) to a string "Result". I show this sting in a multiline textbox in the forms application tha calls this compiler.
These three lines do the trick for you to redirect the output.
Compiler.StartInfo.UseShellExecute = false;
Compiler.StartInfo.RedirectStandardOutput = true;
Compiler.StartInfo.RedirectStandardError = true;
To actually obtain the information, you need to run the application and pick up the output. You need to wait till the application exits to get complete results, the last three lines do that for you:
Compiler.Start();
Result = Compiler.StandardOutput.ReadToEnd() + "\n" + Compiler.StandardError.ReadToEnd();
Compiler.WaitForExit();
Finally, you probably want to suppress the command window to be visible. This code will do that for you:
Compiler.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Compiler.StartInfo.CreateNoWindow = true;

Related

C# WPF application capture python script console output

I have been trying for hours to figure out how to do this but I have a python script that was made into an exe so it acts a console application I'm trying to write a GUI wrapper for it using WPF I have it set up to where it does execute the exe with the command arguments but I want to capture the output from the console and display it in a text box and i can not figure it out. I have tried multiple code snippets but it either does nothing, Outputs after the python exe has finished, or locks up the GUI until the python exe finishes then dumps the completed output to the textbox.
Would someone be able to take a look and see if they can help me with this?
public partial class MainWindow : Window
{
//string output = string.Empty;
private static StringBuilder output = new StringBuilder();
private object syncGate = new object();
private Process process;
private bool outputChanged;
public MainWindow()
{
InitializeComponent();
}
private void RB_Mii_Checked(object sender, RoutedEventArgs e)
{
}
//If we click the button we copy the bin file to the work directory
private void btn_SelMiiQR_Click(object sender, RoutedEventArgs e)
{
//Copy the encrypted.bin file to the working directory
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Input.bin (*.bin)|*.bin|All files (*.*)|*.*";
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
if (openFileDialog.ShowDialog() == true)
{
var fileName = openFileDialog.FileName;
String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
//If the file exists delete the existing file and copy the newone.
if (System.IO.File.Exists(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName)))
{
System.IO.File.Delete(System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
}
System.IO.File.Copy(fileName, System.IO.Path.GetDirectoryName(exePath) + "\\App\\" + System.IO.Path.GetFileName(fileName));
}
}
//If the button was clicked use the input.bin file and attempt to brute force the movable_sedpart1.bin
private void BTN_MIIBF_Click(object sender, RoutedEventArgs e)
{
//If the mfg has input year or no input use it
if (TB_MFGYR.Text.Length == 0 || TB_MFGYR.Text.Length == 4)
{
string DStype = null;
string MFGYR = null;
//Grab the Year if it has value
if (TB_MFGYR.Text.Length == 4)
{
MFGYR = TB_MFGYR.Text;
}
else
{
MFGYR = null;
}
if (RB_N3ds.IsChecked == true)
{
DStype = "new";
}
else if (RB_O3DS.IsChecked == true)
{
DStype = "old";
}
//Execute Command with Arguments
String exePath = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
string dir = System.IO.Path.GetDirectoryName(exePath)+"\\App\\";
//Start the process and export thr console output to the textbox
CreateProcess(dir + "seedminer_launcher.exe", "Mii " + DStype + " " + MFGYR, dir);
}
//Else display Error Message WIP
else
{
tb_outputtext.Text = null;
tb_outputtext.Text = "MFG Year must have 4 characters or none";
}
}
//Execute a new process
private void CreateProcess(string fileName, string arguments, string workdir)
{
// Process process = new Process();
process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir;
process.OutputDataReceived += proc_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
tb_outputtext.ScrollToEnd();
}));
}
private void ReadData()
{
var input = process.StandardOutput;
int nextChar;
while ((nextChar = input.Read()) >= 0)
{
lock (syncGate)
{
output.Append((char)nextChar);
if (!outputChanged)
{
outputChanged = true;
var dispatcher = Application.Current.MainWindow.Dispatcher;
Dispatcher.BeginInvoke(new Action(OnOutputChanged));
}
}
}
lock (syncGate)
{
process.Dispose();
process = null;
}
}
private void OnOutputChanged()
{
lock (syncGate)
{
tb_outputtext.AppendText(output.ToString());
outputChanged = false;
}
}
}
If I understand you correctly then you want your WPF app to continously update the content ot the TextBox while your python executable is running?
I have stripped down your code and used the Windows command ping -t 127.0.0.1 -w 10000 which generates a new line every second to test your code. On my machine your code works as expected: the output in the WPF textbox is updated every second.
What happens if you replace the ping command with your python executable in the code below? Does your python script output a newline character after each line (as mentioned in Process.OutputDataReceived Event)?
MainWindow.xaml.cs
using System;
using System.Diagnostics;
using System.Windows;
namespace SO_Continous_Process_Output
{
public partial class MainWindow : Window
{
private Process process;
public MainWindow()
{
InitializeComponent();
CreateProcess("ping", "-t 127.0.0.1 -w 1000", "");
}
//Execute a new process
private void CreateProcess(string fileName, string arguments, string workdir)
{
// Process process = new Process();
process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = workdir;
process.OutputDataReceived += proc_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
}
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
this.Dispatcher.Invoke((Action)(() =>
{
tb_outputtext.Text = tb_outputtext.Text + "\n" + e.Data;
tb_outputtext.ScrollToEnd();
}));
}
}
}
MainWindow.xaml
<Window x:Class="SO_Continous_Process_Output.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Name="tb_outputtext" Text="{Binding ProcessOutput}"></TextBox>
</Grid>
</Window>
Update
Python script
I wrote a python script to test if the output works and I had to set flush=True in order to make it work.
import time
while True:
print('hi!', flush=True)
time.sleep(1)

How to display output of iperf cmd prompt in textbox

I am using iperf-2.0.5-2-win32 tool to find network bandwidth. I have written codes in c# which opens the cmd prompt, pass iperf parameters to start server side & client side. iperf-2.0.5-2-win32 exe will not open directly, need to open through cmd prompt only.
At present the output(Transfer rate & Bandwidth) is displaying on cmd prompt itself. I want these output to be displayed in textbox
I have tried StreamReader also. But it takes null, I have also tried OutputDataReceived Event, its also taking null.
Found few codes for ipconfig & ping.but those were not working with iperf codes.
button_click event(),
{
Process Client_proc = new Process();
ProcessStartInfo Client_command = new ProcessStartInfo("cmd.exe");
string ip = txtIP.Text;
Client_command.CreateNoWindow = true;
Client_command.WindowStyle = ProcessWindowStyle.Hidden;
Client_command.WorkingDirectory = #"E:\Iperf\RunEXE_Through_Application\iperf-2.0.5-2-win32";
Client_command.Arguments = "/c START iperf -c " + ip;
Client_proc.StartInfo = Client_command;
Client_command.RedirectStandardOutput = true;
Client_command.UseShellExecute = false;
Client_proc.OutputDataReceived += new DataReceivedEventHandler(Client_proc_OutputDataReceived);
Client_proc.Start();
Client_proc.BeginOutputReadLine();
Client_proc.WaitForExit();
}
void Client_proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
string newLine = e.Data.Trim() + Environment.NewLine;
MethodInvoker append = () => txtOutput.Text += newLine;
txtOutput.BeginInvoke(append);
}
}
Plz help me.Earlier responses are appreciated
Thanks
you use this complete code for your disposal
It is not perfect (some problems when using multiple streams )
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());
}
than in your GUI layer you should bind to onDataOutputFromProcess event
there you should have something like
if (screenToPrint.InvokeRequired) //&& this.Visible)
{
try
{
this.Invoke(new Action<AppendToScreenParam>(AppendTextFullConfig), new object[] { append });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return;
}
else
{
screenToPrint.SelectionFont = font;
screenToPrint.SelectionColor = append.Color;
//screenToPrint.AppendText(append.Message);
string TextToPrint = string.Format("{0}\n", append.Message);
screenToPrint.AppendText(TextToPrint);
}
}
Maybe it is because iperf process is returning error. Subscribe the ErrorDataReceived event with Client_proc.ErrorDataReceived += Client_proc_ErrorDataReceived; and see the results. If command returns error, you can see the error message as output.
void Client_proc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
this.txtOutput.BeginInvoke(new MethodInvoker(() => { this.txtOutput.Text = e.Data; }));
}
}

How can I feed commands to cmd.exe process via an input stream manually?

The question sounds a bit, dense. Here is a slightly longer version:
I need to have the main loop wait for user input and also have a process running and waiting for input from a stream to which the user input is to be sent.
Full story: I'm building a Cmd emulator and at first everything looked fine: The user enters a command, it gets echoed to the output area, processed and StdOut and StdErrOut are captured and also added to the output TextBox.
The only problem was, that, as the cmd process was created and started separately for each command, no state was kept. Neither variables nor codepage nor working directory etc..
So I decided to invent a little hack: Entering an opening or closing parenthesis starts and stops collecting the commands instead of executing them. After the closing parenthesis the list of commands ('batch') is used in the processBatch method to feed them all to the cmd process vie its redirected input. Worked fine.
The only problem was, obviously, now I got state but lost immediate response, so any errors wouldn't pop up until the batch was run.
So I decided to combine the good parts and, well, I knew I was heading for trouble when I realized, that to keep two loops working & waiting I have to use threading. Which I haven't done in years..
In the layout I chose the main() loop waits for user input and startCMDtask() runs startCMD() in a task. Here the input stream is scanned until is has data and then the cmd process is to process them..
But it doesn't work.
List<string> batch = new List<string>();
public volatile string output = "+";
public volatile string outputErr = "-";
Process CMD;
Task cmdTask;
volatile Queue<string> cmdQueue = new Queue<string>();
volatile public bool CMDrunning = false;
Tthis works just fine
private void processBatch()
{
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
foreach(string line in batch) sw.WriteLine(line);
}
output = "^"; outputErr = "~";
try { output = p.StandardOutput.ReadToEnd(); } catch { }
try { outputErr = p.StandardError.ReadToEnd(); } catch { }
try { p.WaitForExit(); } catch { }
tb_output.AppendText(output + "\r\n" + outputErr + "\r\n");
}
These don't quite, but almost..
private void setupCMD()
{
CMD = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
// info.Arguments = "/K"; // doesn't make a difference
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
CMD.StartInfo = info;
}
private void startCMDtask()
{
var task = Task.Factory.StartNew(() => startCMD());
cmdTask = task;
}
private void startCMD()
{
try { CMD.Start(); CMDrunning = true; }
catch { output = "Error starting cmd process.\r\n"; CMDrunning = false; }
using (StreamWriter sw = CMD.StandardInput)
{
if (sw.BaseStream.CanWrite)
do {
try
{
string cmd = cmdQueue.Dequeue();
if (cmd != null & cmd !="")
{
sw.WriteLine(cmd);
processOutputStreams();
}
}
catch {}
} while (CMDrunning);
}
private void processOutputStreams()
{
string newOutput = ""; string newOutputErr = "";
while (CMD.StandardOutput.Peek() > 0)
newOutput += (char)(CMD.StandardOutput.Read());
newOutput += "!?"; // at this point stdout is correctly captured (1)
try {
while (CMD.StandardError.Peek() > 0) // from here execution jumps away (2)
{ newOutputErr += (char)(CMD.StandardError.Read()); }
} catch {
newOutputErr = "?"; // never comes here
}
lock (output) // no noticable difference
lock (outputErr) //
{ // if I jump here (3) from (1) the result is displayed
// but not if i comment out the 2nd while loop (2)
if (newOutput != null & newOutput != "") output += newOutput + "\r\n";
if (newOutputErr != null & newOutputErr != "") outputErr += newOutputErr + "\r\n";
}
}
This is the call from the input processor in the main thread:
lock (cmdQueue) cmdQueue.Enqueue(cmd);
I have no idea which part is the problem: the process, the cmd shell, the input stream, the output stream, the threading, the locks or all of it in turns..??
I finally got it working. The reason for the erratic behaviour I described in the code samples was that the 3 streams were not accessed in an async'ed manner.
To rectify I discarded the processOutput function and replaced it by two calls that the process itself triggers. MS documetation gives a fine example here
I also made the StreamWriter sync, that feeds the process and the whole task it runs in as well.
Here is the new code:
private void startCMDtask()
{
var task = Task.Factory.StartNew(() => startCMD());
cmdTask = task;
}
private async void startCMD()
{
try { CMD.Start(); CMDrunning = true; }
catch { cmdErrOutput.Append("\r\nError starting cmd process.");
CMDrunning = false; }
CMD.BeginOutputReadLine();
CMD.BeginErrorReadLine();
using (StreamWriter sw = CMD.StandardInput)
{
if (sw.BaseStream.CanWrite)
do {
try
{
string cmd = cmdQueue.Dequeue();
if (cmd != null & cmd !="") await sw.WriteLineAsync(cmd);
}
catch { }
} while (CMDrunning);
try { CMD.WaitForExit(); }
catch { cmdErrOutput.Append("WaitForExit Error.\r\n"); }
}
}
This is how the process is set up now:
private void setupCMD()
{
CMD = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
CMD.OutputDataReceived += new DataReceivedEventHandler(cmdOutputDataHandler);
CMD.ErrorDataReceived += new DataReceivedEventHandler(cmdErrorDataHandler);
cmdOutput = new StringBuilder();
cmdErrOutput = new StringBuilder();
CMD.StartInfo = info;
}
And here are the output handlers:
private static void cmdOutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{ // Add the text to the collected output.
cmdOutput.Append(Environment.NewLine + outLine.Data);
}
}
private static void cmdErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{ // Add the text to the collected error output.
cmdErrOutput.Append(Environment.NewLine + outLine.Data);
}
}
At the end of the user input porcessing this is how the input queue is ged and the output fetched:
cmdUnDoStack.Push(cmd);
Application.DoEvents();
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => updateOutputArea(uiScheduler));
Using this little routine:
private void updateOutputArea(TaskScheduler uiScheduler)
{
Task.Factory.StartNew(() =>
{
tb_output.AppendText(cmdOutput + "\r\n" + cmdErrOutput + "\r\n");
cmdOutput.Clear();
cmdErrOutput.Clear();
}, System.Threading.CancellationToken.None, TaskCreationOptions.None, uiScheduler);
}
And now for the special treament some of the good old commands like CLS or COLOR need.. ;-)

How to run new process after the old process finish, without hang the application

I working on Visual Studio 2010, C# (.Net 4).
I have an application that contain a DataGridView with two columns. Each column contain argument for the program I want to run.
Now I want to run from my C# application another application with parameters from the data grid view.
In additional, I want to wait 3 seconds before running new process.
I try the follow code, but the process runs parallelly and not one after one:
private static Mutex mut = new Mutex();
public void runProgram(string executablePath, string argu1, string argu2)
{
mut.WaitOne();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = Path.GetDirectoryName(executablePath);
startInfo.FileName = "CMD.exe";
startInfo.Arguments = "/C " + set.ExecutablePath + " "
+ argu1 + " " + argu2;
try
{
Process p = Process.Start(startInfo);
//p.WaitForExit(); // don't start the next process until the first finish -> not good, stuck the app
}
catch
{
MessageBox.Show("ERROR: unsuccess to run the applicition");
}
mut.ReleaseMutex();
}
private void bu_RunProgram_Click(object sender, EventArgs e)
{
if (!File.Exists(set.ExecutablePath))
{
MessageBox.Show("The executable file doesn't exist\nPlease select right executable file in the settings form", "Error");
return;
}
int progRow;
foreach (DataGridViewRow dgvr in dg_ParametersToRun.Rows)
{
progRow = dgvr.Index;
string argu1 = dg_ParametersToRun.Rows[progRow].Cells[0].FormattedValue.ToString();
string argu2 = dg_ParametersToRun.Rows[progRow].Cells[1].FormattedValue.ToString();
Thread threadProgRun= new Thread(() => runProgram(set.ExecutablePath, argu1, argu2));
threadProgRun.Start();
Thread.Sleep(3000); // Need to come to this line only when the previous thread finish...
}
}
To be honest, I've never worked with threads..
Thank you!
UPDATE CODE (According the suggestion):
// Aid variable
int paramRowIndex;
public void runNextParameters(object sender, EventArgs e)
{
paramRowIndex++;
if (paramRowIndex > dg_RunListTests.Rows.Count) return; finish run all parameters
//run the test
string argu1 = dg_RunListTests.Rows[paramRowIndex].Cells[0].FormattedValue.ToString();
string argu2 = dg_RunListTests.Rows[paramRowIndex].Cells[1].FormattedValue.ToString();
runParameters(set.ExecutablePath, componenet, test);
}
public void runParameters(string executablePath, string argu1, string argu2)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = Path.GetDirectoryName(executablePath);
startInfo.FileName = "CMD.exe";
startInfo.Arguments = "/C " + set.ExecutablePath + " "
+ argu1 + " " + argu2;
try
{
Process p = Process.Start(startInfo);
p.Exited += runNextParameters;
}
catch
{
MessageBox.Show("Unsuccess to run the test again");
}
}
private void bu_RunParameters_Click(object sender, EventArgs e)
{
if (!File.Exists(set.ExecutablePath))
{
MessageBox.Show("The executable file doesn't exist\nPlease select right executable file in the settings form", Error);
return;
}
paramRowIndex = 0;
runNextParameters(sender, e);
}
Possible fast solution: start a .bat file that starts the two(three) programs. You have to create another program that waits 3 seconds to call in between.

Running Command line from an ASPX page, and returning output to page

I'm trying to access the command line and execute a command, and then return the output to my aspx page. A good example would be running dir on page load of an aspx page and returning the output via Response.Write(). I have tried using the code below. When I try debugging this it runs but never finishes loading and no output is rendered.
I am using C# and .NET Framework 3.5sp1. Any help much appreciated.
Thanks,
Bryan
public partial class CommandLine : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Process si = new System.Diagnostics.Process();
si.StartInfo.WorkingDirectory = #"c:\";
si.StartInfo.UseShellExecute = false;
si.StartInfo.FileName = "cmd.exe";
si.StartInfo.Arguments = "dir";
si.StartInfo.CreateNoWindow = true;
si.StartInfo.RedirectStandardInput = true;
si.StartInfo.RedirectStandardOutput = true;
si.StartInfo.RedirectStandardError = true;
si.Start();
string output = si.StandardOutput.ReadToEnd();
si.Close();
Response.Write(output);
}
}
You have a problem with the syntax of commandline arguments to cmd.exe. This is why cmd never exits.
In order to have cmd.exe run a program and then quit, you need to send it the syntax "/c [command]". Try running the same code with the line
si.StartInfo.Arguments = "dir";
replaced with
si.StartInfo.Arguments = "/c dir";
and see if it works.
Most likely your problem is with the permissions. The user under which ASP.NET process runs is with very limited rights.
So, either you have to set the proper permissions for that user, or run ASP.NET under some other user.
This hides a security risks though, so you have to be very careful.
This is madness! Use the System.IO namepace to create your file list from inside your C# program! It's very easy to do; although this technique also has authorization issues.
Use System.Diagnostics.Process.
Here is some ASP.NET code shelling out to run subversion commands on the command line.
///////////////////////////////////////////////////////////////////////
public static string run_svn(string args_without_password, string svn_username, string svn_password)
{
// run "svn.exe" and capture its output
System.Diagnostics.Process p = new System.Diagnostics.Process();
string svn_path = Util.get_setting("SubversionPathToSvn", "svn");
p.StartInfo.FileName = svn_path;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
args_without_password += " --non-interactive";
Util.write_to_log ("Subversion command:" + svn_path + " " + args_without_password);
string args_with_password = args_without_password;
if (svn_username != "")
{
args_with_password += " --username ";
args_with_password += svn_username;
args_with_password += " --password ";
args_with_password += svn_password;
}
p.StartInfo.Arguments = args_with_password;
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
p.WaitForExit();
stdout += p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
if (error != "")
{
Util.write_to_log(error);
Util.write_to_log(stdout);
}
if (error != "")
{
string msg = "ERROR:";
msg += "<div style='color:red; font-weight: bold; font-size: 10pt;'>";
msg += "<br>Error executing svn.exe command from web server.";
msg += "<br>" + error;
msg += "<br>Arguments passed to svn.exe (except user/password):" + args_without_password;
if (error.Contains("File not found"))
{
msg += "<br><br>***** Has this file been deleted or renamed? See the following links:";
msg += "<br><a href=http://svn.collab.net/repos/svn/trunk/doc/user/svn-best-practices.html>http://svn.collab.net/repos/svn/trunk/doc/user/svn-best-practices.html</a>";
msg += "<br><a href=http://subversion.open.collab.net/articles/best-practices.html>http://subversion.open.collab.net/articles/best-practices.html</a>";
msg += "</div>";
}
return msg;
}
else
{
return stdout;
}
}

Categories

Resources