I'm currenty trying to write a GUI around
First I run a command to start the actual conversion of a image.
After that method I want to move the converted file to a different folder by MoveFile().
The problem is that the program doesn't wait for the CMD process to be finished and it wants to move the file immediately. When I'm debugging the program and actually letting it finish the CMD command, the file will be moved with no problems.
From reading online I need to use .WaitForExit() but it doesn't seem to do much.
RunCommand(strCommand);
MoveFile(strDirectoryName + "\\" + strNewName, strDirectoryName + "\\0 - Preview\\" + strNewName);
RunCommand()
private void RunCommand(string CmdText) {
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
//startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/c " + CmdText;
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
}
Any helpers?
Found the issue.
Had to put a small Thread.Sleep between the actual finishing of the CMD command and the moving of the file.
you have 2 easy ways to do that:
var1: you can use the static method
Process.Start(your_file, your_args).WaitForExit();
var2: Use the Exited event.
var p = new Process() { EnableRaisingEvents = true };
p.StartInfo.FileName = your_file;
p.StartInfo.Arguments = your_args;
p.Exited += (sender, e) =>
{
your_next_step
};
p.Start();
on P_Exited you can write the next step
Related
I currently have a portion of code that creates a new Process and executes it from the shell.
Process p = new Process();
...
p.Start();
p.WaitForExit();
This keeps the window open while the process is running, which is great. However, I also want to keep the window open after it finishes to view potential messages. Is there a way to do this?
It is easier to just capture the output from both the StandardOutput and the StandardError, store each output in a StringBuilder and use that result when the process is finished.
var sb = new StringBuilder();
Process p = new Process();
// redirect the output
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
// hookup the eventhandlers to capture the data that is received
p.OutputDataReceived += (sender, args) => sb.AppendLine(args.Data);
p.ErrorDataReceived += (sender, args) => sb.AppendLine(args.Data);
// direct start
p.StartInfo.UseShellExecute=false;
p.Start();
// start our event pumps
p.BeginOutputReadLine();
p.BeginErrorReadLine();
// until we are done
p.WaitForExit();
// do whatever you need with the content of sb.ToString();
You can add extra formatting in the sb.AppendLine statement to distinguish between standard and error output, like so: sb.AppendLine("ERR: {0}", args.Data);
This will open the shell, start your executable and keep the shell window open when the process ends
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "CMD.EXE";
psi.Arguments = "/K yourmainprocess.exe";
p.StartInfo = psi;
p.Start();
p.WaitForExit();
or simply
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "CMD.EXE";
psi.Arguments = "/K yourmainprocess.exe";
Process p = Process.Start(psi);
if(p != null && !p.HasExited)
p.WaitForExit();
Be carefull espacially on switch /k, because in many examples is usually used /c.
CMD /K Run Command and then return to the CMD prompt.
CMD /C Run Command and then terminate
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/k yourmainprocess.exe";
p.Start();
p.WaitForExit();
Regarding: "Member Process.Start(ProcessStartInfo) cannot be accessed with an instance reference; qualify it with a type name instead"
This fixed the problem for me....
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "CMD.EXE";
psi.Arguments = "/K yourmainprocess.exe";
Process p = Process.Start(psi);
p.WaitForExit();
Thanks to #user2526830 for the code. Based on that code I added few lines to my program since I want to read the output of the SSH command. Below is my code which gives an error at line while
StandardOut has not been redirected or the process hasn't started yet.
What I want to achieve is that I want to read the output of ls into a string.
ProcessStartInfo startinfo = new ProcessStartInfo();
startinfo.FileName = #"f:\plink.exe";
startinfo.Arguments = "-ssh abc#x.x.x.x -pw abc123";
Process process = new Process();
process.StartInfo = startinfo;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.StandardInput.WriteLine("ls -ltr /opt/*.tmp");
process.StandardInput.WriteLine("exit");
process.StartInfo.RedirectStandardOutput = true;
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
}
process.WaitForExit();
Console.ReadKey();
Try setting standard output redirection before starting the process.
process.StartInfo.RedirectStandardOutput = true;
process.Start();
It might be that the process already terminated when you try to read the output (dues to your "exit" command). Try the below slightly modified version where I moved your while loop after the "ls" command but before the "exit" command.
It should read the output of your "ls" command fine, but unfortunately will most probably hang at some point as you will never get EndOfStream on the StandardOutput. When there is nothing more to read, ReadLine will block until it can get read another line.
So unless you know how to detect the last line of the output generated by your command and break out of the loop after you read it, you may need to use a separate thread either for reading or for writing.
ProcessStartInfo startinfo = new ProcessStartInfo();
startinfo.FileName = #"f:\plink.exe";
startinfo.Arguments = "-ssh abc#x.x.x.x -pw abc123";
Process process = new Process();
process.StartInfo = startinfo;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
process.StandardInput.WriteLine("ls -ltr /opt/*.tmp");
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
}
process.StandardInput.WriteLine("exit");
process.WaitForExit();
Console.ReadKey();
I'm looking to trigger the child command window's close event once its command is finished. Keep in mind, it's a background process initiated from a console app so it's never visible. What is visible is the console application.
I tried using the Exited event, but that didn't work. I tried relying on CMD to know when to close it by using /c, /k, and exit. Neither seem to work. I also tried a do while loop checking HasExited, none of these have worked unless I type "exit" within the application console window. It does not close, but somehow triggers the invisible child command windows to close.
Is there another way of closing it once the child command is complete?
String msg = "echo %time%; exit;";
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = msg;
p.EnableRaisingEvents = true;
p.Exited += p_Exited;
p.Start();
msg += p.StandardOutput.ReadToEnd();
Thank you very much!!
I modified your program slightly to run a child command processor, capture its output, then write it to console.
char quote = '"';
string msg = "/C " + quote + "echo %time%" + quote;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = msg;
p.EnableRaisingEvents = true;
p.Exited += (_, __) => Console.WriteLine("Exited!");
p.Start();
string msg1 = p.StandardOutput.ReadToEnd();
Console.WriteLine(msg1);
Here's a full program, using slightly different syntax, but similar in spirit:
using System;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
char quote = '"';
var startInfo = new ProcessStartInfo("cmd", "/C " + quote + "echo %time%" + quote)
{ UseShellExecute = false, RedirectStandardOutput = true };
var process = new Process { EnableRaisingEvents = true };
process.StartInfo = startInfo;
process.Exited += (_, __) => Console.WriteLine("Exited!");
process.Start();
string msg1 = process.StandardOutput.ReadToEnd();
Console.WriteLine(msg1);
Console.ReadLine();
}
}
}
Or, as this answer illustrates, maybe just call DateTimeOffset.Now. If you're interested in looking at sub-second info, maybe use Stopwatch class instead.
If you prefer to drive command line with commands from C#, it's also possible. Igor Ostrovsky describes how to convert events to Tasks; then use async/await to create a procedural-looking sequence of commands and responses.
I have the following code in my C# application which loaded a batch file silently using command prompt and executed and returned the result to a string:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = #"C:\files\send.bat";
proc.StartInfo.RedirectStandardError = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
string strGetInfo = proc.StandardOutput.ReadToEnd();
strCMDOut = strGetInfo.Substring(strGetInfo.Length - 5, 3);
proc.WaitForExit();
I am trying to avoid my application going out to a different file to execute the batch file, rather I wanted to embed it inside my application. So I changed the above code to this:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "#ECHO ON java com.this.test567 send";
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
proc.StartInfo = startInfo;
proc.Start();
string strGetInfo = proc.StandardOutput.ReadToEnd();
strCMDOut = strGetInfo.Substring(strGetInfo.Length - 5, 3);
When the code executes, I can see the command prompt window for a brief moment before it closes and the execution is not working correctly. How can I fix the issue?
Instead of using cmd.exe just use java directly, you should also redirect standard error and check that after the process ends.
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = #"java.exe";
proc.StartInfo.Arguments = "com.this.test567";
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
string strGetInfo = proc.StandardOutput.ReadToEnd();
if(string.IsNullOrEmpty(strGetInfo))
strGetInfo = proc.StandardError.ReadToEnd();
proc.WaitForExit();
Note that by calling cmd directly, you're effectively making a batch script with whatever you use for in the Arguments Property. Like a .bat file, the command window closes as soon as it's done. To fix this, add a pause command to the end.
startInfo.Arguments = "#ECHO ON java com.this.test567 send\npause";
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
so seperate commands with &
"/k #ECHO ON&java com.this.test567&send"
/k keeps a window open.
so you'll get in cmd
cmd /k #ECHO ON&java com.this.test567&send
I'm running a program using command line in c# this program produce some logs while its running in need to display this logs whenever it get change. I wrote the following code but it shows all the logs once the process has been killed and during the running time my program is not responding. how can I fix it?
regards
ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + "C:\\server.py");
Process proc = new Process();
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
procStartInfo.UseShellExecute = false;
procStartInfo.RedirectStandardOutput = true;
//procStartInfo.CreateNoWindow = true;
proc.StartInfo = procStartInfo;
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(300);
LogstextBox.Text = output;
Edited:
well, I tried to use OutputDataReceived but it doesn't show any result, here is the changed code:
{
//processCaller.FileName = #"ping";
//processCaller.Arguments = "4.2.2.4 -t"; this is working
processCaller.FileName = #"cmd.exe";
processCaller.Arguments = "/c c:\\server.py"; //this is not working
processCaller.StdErrReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.StdOutReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.Completed += new EventHandler(processCompletedOrCanceled);
processCaller.Cancelled += new EventHandler(processCompletedOrCanceled);
this.richTextBox1.Text = "Server Started.." + Environment.NewLine;
processCaller.Start();
}
private void writeStreamInfo(object sender, DataReceivedEventArgs e)
{
this.richTextBox1.AppendText(e.Text + Environment.NewLine);
}
This is the problem:
string output = proc.StandardOutput.ReadToEnd();
You won't get to the "end" of standard output until the process has terminated.
You should be reading a line at a time - or possibly just subscribing to the OutputDataReceived event (and following the documented other requirements for that event).
EDIT: Here's sample code which works for me:
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
public static void Main()
{
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/c " + "type Test.cs")
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process process = Process.Start(startInfo);
process.OutputDataReceived += (sender, e) => Console.WriteLine(e.Data);
process.BeginOutputReadLine();
process.WaitForExit();
// We may not have received all the events yet!
Thread.Sleep(5000);
}
}
Note that in your sample code, you're accessing the UI on whatever thread the OutputDataReceived handler is called - that looks like a bad idea to me.
You can use the Process.BeginOutputReadLine Method. The link shows a complete working example in C# which uses the OutputDataReceived event. That code example should do what you want.