So for my recent project I need to put the content generated by A console app in a WPF textBox.
The point is the app generates the text file (test.txt) only after process completion which can take some time.
Here's the code for the same:
foreach (var website in lst) //list can have several entries.
{
var args = "-v -all -text test.txt n" + website.ToString() + " 443";
Process.Start(#"C:\TestSSLServer.exe", args);
Task.Factory.StartNew(() =>
{
MyValue = System.IO.File.ReadAllText(#"C:\test.txt");
});
}
How do I make sure that the text box is only populated when the console app TestSSLServer quits?
Edit: Process.WaitForExit(); does not work. I tried it :( Still throws file not found exception.
Thanks.
You can use Process.WaitForExit() to block until the process exits.
Process p = Process.Start(#"C:\TestSSLServer.exe", args);
p.WaitForExit();
I would note that this will block whatever thread it's run on. If you want to be notified when the process exits instead use the Process.Exited event.
You need to store the process in a variable of type Process. Then you can set its EnableRaisingEvents flag to true and subscribe to the event signaling that the process has ended. Your handler should be the function which populates the text box.
Sample code is available on MSDN.
https://msdn.microsoft.com/en-us/library/system.diagnostics.process.exited(v=vs.110).aspx
Related
I have a C# Console application which I am trying to execute from another WinForm application just like batch runner by giving the console application's .exe file like below.
Process.Start("Path of Console application exe to execute")
However I need to wait and handle the output and display the output in WinForm's richtextbox from console application once it has completed the execution. How can I achieve this?
Update
I have changed the code to Start a Process and Read using StandardOutput and BeginOutputReadLine() to Read the output asynchronously, but not able to see output in console window, instead console window is getting closed. Not sure how to solve this.
p.StartInfo.UseShellExecute = false;
// p.StartInfo.CreateNoWindow = True
p.StartInfo.RedirectStandardOutput = true;
string #out = null;
p.StartInfo.RedirectStandardError = true;
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
#out += e.Data;
});
p.StartInfo.FileName = currentTest;
p.Start();
p.BeginOutputReadLine();
// string output = p.StandardError.ReadToEnd();
// p.WaitForExit()
while (!p.HasExited)
Application.DoEvents();
//Console.WriteLine($#"Output \n'{output.Substring(output.Length - 50)}'");
Console.WriteLine($#"\n Error stream: {#out}");
Console.ReadLine();
You need to redirect stdout (and probably stderr) so that any output comes to you, instead of a console; you may also want to redirect stdin. All of these things are available via ProcessStartInfo, with an example on MSDN. Note that if you want to display updates while the exe is running, you may need a worker thread to read incrementally from StandardOutput and StandardError, rather than ReadToEnd() - which won't return anything at all until the associated output pipe is closed.
However! If the console exe is "yours", it may be simpler to just expose the functionality you want in a library, and invoke it directly in-process. There are times when out-of-process is actively preferred, such as when you need to allow that process to go catastrophically wrong in some scenarios - but usually in-process is preferable, given free rein.
i am invoking an exe via c# Diagnostics.Process class and read output from it's StdOut. The process is forcefully terminated in case it doesn't automatically terminates in a specified time, something like:
process.StartInfo.FileName = #"D:\t.exe";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
process.WaitForExit(500);
if (!process.HasExited)
{
process.Kill();
process.WaitForExit();
}
string stdOutContents = process.StandardOutput.ReadToEnd();
Now the problem is the code works succesfully when the exe terminates normally. But in case it fails to terminate normally (usually the exe gets stuck in an infinite loop somewhere), stdOutContents is read as an empty string.
How can i read StdOut after the process is killed (without using process.OutputDataReceived event technique)? (It has been verified that the exe-in-question does always writes something onto StdOut even if it gets stuck somewhere).
Update 1
Details about Exe which is being invoked (refereed as 'native app' across this question)
It is a small utility implemented in c language and compiled using MS C++ compiler. It does its job while simultaneously outputting status information onto the StdOut (using putchar).
There are only two possible cases of operation:
It will run successfully while simultaneously printing some data onto the StdOut.
It will run normally to a certain point (simultaneously outputting data on StdOut) and then get stuck in an infinite loop. (This is an acceptable behavior).
Both scenarios have been verified using cmd.
Details about new attempts
i wrote a c# app (referred as dummy app) which mimics the native app behavior and this code works fine. However when run for the native app, i get nothing at all.
i don't understand why the code cant read the contents outputted by the native app?
i also tried using event handler for OutputDataReceived. It gets called only once with args.Data = null when the code tries to kill the process. Inspecting the behavior for dummy app revealed that when process.kill is called, the handler is invoked with args.Data = null. So this seems to be a standard behavior of sorts for both apps.
i also tried changing the newline characters for native app. Since it is implemented in c language, it uses \n for newline. i tried using both \r\n pair for newline but StdOut is still blank (for case 2).
I had the same interrogation and the doc of Process.Kill says
Data edited by the process or resources allocated to the process can be lost if you call Kill.
Which seems to indicate that you cannot rely on reading the StandardOutput of a process, although it is not clearly stated that the output / error streams are disposed.
I finally got inspired by this answer
How to spawn a process and capture its STDOUT in .NET?
and I use the following code :
var info = new ProcessStartInfo("some.exe");
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
using (var p = new Process())
{
p.StartInfo = info;
var output = new StringBuilder();
p.OutputDataReceived += (sender, eventArgs) =>
{
output.AppendLine(eventArgs.Data);
};
p.Start();
p.BeginOutputReadLine();
if (!p.WaitForExit(5000))
{
Console.WriteLine("Taking too long...");
p.Kill();
Console.WriteLine("Process killed, output :\n" + output);
}
}
Same pattern can be used with the ErrorDataReceived
Note that one could miss some unflushed output from the child process, however in my case I don't expect much from a process that requires to be killed, at most some information for debugging purposes.
I have a application which will open a two microsoft ppsx file one after another. for that i have used process object to run the files. mention bellow
Process process = Process.Start(#"E:\test\test.ppsx");
I need to run the files in such a way that after finishing the first file ,second file should run automatically. can some one suggest me how can achieve that.
You can use WaitForExit method to wait to end process (Something like this):
var process1 = Process.Start(...);
process1.WaitForExit();
var process2 = Process.Start(...);
or subscribe into a Process.Exited event and execute another process after the first one. Check this for your reference.
You can use Process.WaitForExit method.
Instructs the Process component to wait indefinitely for the
associated process to exit.
Also check Process.Exited event.
Occurs when a process exits.
Process process = Process.Start(#"E:\test\test.ppsx");
process.WaitForExit();
Use Process.WaitForExit()
class Program
{
static void Main(string[] args)
{
Task.Run(() =>
{
Process.Start(#"c:\temp\presentation1.pptx").WaitForExit();
}).ContinueWith(o =>
{
Process.Start(#"c:\temp\presentation2.pptx").WaitForExit();
});
Console.ReadKey();
}
}
You should get all the ppsx files from the test directory in the E drive in an array and process on the array of ppsx files according to your requirements.
string[] files = Directory.GetFiles("your path");
loop through the array and pass each file path to the Process constructor and as lexeRoy said you can WaitForExit.
there are a lot of examples that show how to redirect the stdout of another application. However I would like to let the application keep its stdout and only retrieve a copy of the stdout in my parent process. Is this possible?
My scenario: I have some tests (using Visual Studio Test Runner) which start an external process (server) to do their testing. The server outputs a lot of useful debug information in its stdout which I would like to include in my test results.
I can capture the process output and output it via Trace.WriteLine to let it show up in the test details later. However it would be nice to see the server window with its output while the test is running to see the current progress (test can be running a long time).
So I'm looking for ways to copy this information instead of simply redirecting it.
Any ideas?
Would this work for you?
var outputText = new StringBuilder();
var errorText = new StringBuilder();
using (var process = Process.Start(new ProcessStartInfo(
#"YourProgram.exe",
"arguments go here")
{
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false
}))
{
process.OutputDataReceived += (sendingProcess, outLine) =>
{
outputText.AppendLine(outLine.Data); // capture the output
Console.Out.WriteLine(outLine.Data); // echo the output
}
process.ErrorDataReceived += (sendingProcess, errorLine) =>
{
errorText.AppendLine(errorLine.Data); // capture the error
Console.Error.WriteLine(errorLine.Data); // echo the error
}
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
// At this point, errorText and outputText StringBuilders
// have the captured text. The event handlers already echoed the
// output back to the console.
}
What about writing a small program that forwards STDIN to STDOUT, while at the same time doing something else with it as well?
You could then replace the command that starts the server process with one that starts it and pipes its output to the above utility. That way you 'll have both programmatic access to the output and see it in real time in the output window.
I want to run a console application (eg app.exe) from a windows form load event.
I'v tried System.Diagnostics.Process.Start(), But after it opens app.exe, it closes it immidiately.
Is there any way that I can run app.exe and leave it open?
If you are just wanting the console window to stay open, you could run it with something like this command:
System.Diagnostics.Process.Start( #"cmd.exe", #"/k c:\path\my.exe" );
Try doing this:
string cmdexePath = #"C:\Windows\System32\cmd.exe";
//notice the quotes around the below string...
string myApplication = "\"C:\\Windows\\System32\\ftp.exe\"";
//the /K keeps the CMD window open - even if your windows app closes
string cmdArguments = String.Format("/K {0}", myApplication);
ProcessStartInfo psi = new ProcessStartInfo(cmdexePath, cmdArguments);
Process p = new Process();
p.StartInfo = psi;
p.Start();
I think this will get you the behavior you are trying for. Assuming you weren't just trying to see the output in the command window. If you just want to see the output, you have several versions of that answer already. This is just how you can run your app and keep the console open.
Hope this helps. Good luck.
If app.exe does nothing, or finishes its work quickly (i.e. simply prints "Hello World" and returns), it will behave the way you just explained. If you want app.exe to stay open after its work is done, put some sort of completion message followed by Console.ReadKey(); in the console application.
If you can change the code of app.exe, just add Console.In.Read() to make it wait for a key press.
app.exe can end with Console.ReadLine() assuming it too is a C# application where you control the source code.
You have one of two problems, given your master/slave application setup:
Your master app is opening, displaying a form, that form runs the slave app and closes immediately, even though the slave app is still running.
Your master app is opening, displaying a form, that form runs the slave app which closes immediately.
For the first problem, you need to wait/block for the process to complete (i.e. Process.WaitForExit().
For the second problem, it sounds like the slave app has done what it needs to (or thrown an exception) and is closing immediately. Try running it with the same parameters from a command prompt and check the output.
If you have control over app.exe, you should be aware of how it functions so I will assume that you do not have control over it's inner workings. In that case, you can try passing a help flag which may or may not give you more info on how to call app.exe. Try something like this:
private startApp()
{
string command = " -h"; //common help flag for console apps
System.Diagnostics.Process pRun;
pRun = new System.Diagnostics.Process();
pRun.EnableRaisingEvents = true;
pRun.Exited += new EventHandler(pRun_Exited);
pRun.StartInfo.FileName = "app.exe";
pRun.StartInfo.Arguments = command;
pRun.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
pRun.Start();
pRun.WaitForExit();
}
private void pRun_Exited(object sender, EventArgs e)
{
//Do Something Here
}
Create a new text file, name it app.bat and put this in there:
app.exe
pause
Now have your form point to that bat file.
In your console application, type:
Console.ReadLine(); - Use this piece of code to wait until you press enter
Console.ReadKey(); - Use this code to wait until you press a key