Synchronization between two processes in C# - c#

I have a WPF application, on a button click I starts 2 process (P1 and P2), both runs on command propmt and I am able to redirect the output of both process to the TextBox in my WPF application.
(reading output asynch).
But the output is getting mix because I am not doing WaitForProcess neither for P1 nor for P2 (I dont want UI to get hang).
I want P2 to start after P1 gets over.
For That I am checking if Process P1 exists or not then only start Process P2.
But my UI gets hangs and nothing is coming up.
in the Windows Task bar
Process P1 is running but Textbox is not getting updated.

When you initialise a Process object, you can register a handler for the Process.Exited event. As you might imagine, this event gets raised when the relevant process gets terminated, so you can start your second Process from there:
Process process = new Process();
process.EnableRaisingEvents = true;
...
process.Exited += Process_Exited;
...
private void Process_Exited(object sender, EventArgs e)
{
// First Process has completed - start second process here
}

Related

WPF: Send arguments to a background thread and get output after it is started

I have a deep-learning model written with python and it needs a path of a video as its input. I am trying to create a GUI for this model using WPF, and the model has been converted to an application file.
Because the time for model to import packages is too long, I want to start a process of the python application file while initialising the WPF main window. Then, I can record a video and send a path of this video to this process, and after I get a output from this model, I can recording an another video and send a new path to the model again.
I have tried using backgroundworker and thread, but both of them can only send arguments when the process is initialised, and neither of them can send arguments to the background process while the process is being executed. And Only after the process is finished, I can get the output from the background thread.
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
Process p_exe = new Process();
p_exe.StartInfo.FileName = #"C:/dist/predict/predict.exe";
p_exe.StartInfo.UseShellExecute = false;
p_exe.StartInfo.RedirectStandardOutput = true;
p_exe.StartInfo.RedirectStandardInput = true;
p_exe.StartInfo.CreateNoWindow = true;
p_exe.StartInfo.Arguments = e.Argument.ToString();
p_exe.Start();
e.Result = p_exe.StandardOutput.ReadToEnd();
p_exe.WaitForExit();
p_exe.Close();
}
How can I send arguments to and get output from the background thread while the process is being executed?

Process ends prematurely when executed from a GUI, doesn't when executed via a Console testing app

I'm sorry if the title is not matching the precise description of the issue I'm facing, I accept suggestions for edits.
I'm developing a component that, when called, shall start a Process and wait for it to complete. The Process might want to redirect std output to a custom winform (a popup) for the user to have a feedback on the Process status.
In order to test the component before implementing it in the official application, I've developed a Console app that calls the module, in the same way the official application will do accepting user input from the GUI --> not the popup, the application main window.
When tested in the Console app, everything works as I expect. When testing in the official GUI application, the Process ends prematurely, with exit code 0 (all fine). I mean, it prints something in the user winform, up to a certain point, always the same point, then exits.
I can't understand why or how to identify root causes and maybe do something about it. I'm looking for help, hereafter the module source code for process execution:
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = myExePath;
processStartInfo.Arguments = myExeArguments;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = false;
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = true;
using (Process process = Process.Start(processStartInfo))
{
process.EnableRaisingEvents = true;
// accessory code. Issue is reproduced even without this section ---- //
Thread t = new Thread(() =>
{
// show a custom winform for the user to read
});
t.Start();
// ------------------------------------------ //
process.OutputDataReceived += (s, a) => {
// Do something with a.Data
};
process.BeginOutputReadLine();
process.WaitForExit();
}
EDIT:
let's say that the Process myExe should print something to stdout. I read this something and it goes along these lines:
line 1
line 2
I'm doing something
line 3
start doing something else <-- when component is integrated in official application, here Process Exits without exceptions
line 4
line 5 <-- When component is tested in Console app, here is where Process Exits without exceptions.
I should read up to line 5 in both testing scenario and official scenario.

Process.StartInfo clarifications c#

I'm trying to run another process from the main one using Process class.
AudioRecordProcess = new Process();
AudioRecordProcess.StartInfo.UseShellExecute = false;
AudioRecordProcess.StartInfo.FileName = #"RecordAudio\RecordAudio";
AudioRecordProcess.StartInfo.CreateNoWindow = true;
The process starts fine but:
Even if I set CreateNoWindow property when I run the code a window is created (the other process is a WPF project with just the main window);
When I try to close the process with closemainwindow it does close nothing. The window just goes under the main process' one.
If I try to kill the process from code it doesn't execute the instructions in my event closing main window, but if I close it from the taskbar it executes that routine. Shouldn't the actions be the same?
Any idea for this strange behavior?
Thanks
Class 'Process' is used to create and/or control and monitor specific process.
Only console application will obey CreateNoWindow = true, while
Windows Forms and WPF applications will ignore it.
Since you have started another process on the system, that process
will continue on its own and will not be terminated once you stop
parent process. However there are some resource lingering (especially
thread and handle related) in the parent process which prevents
parent process termination when its main window is closed.
killing interrupts normal process execution and forces stop as soon
as possible therefore it is normal that closing handlers are not
executed
EDIT:
For test create WPF application and put following code in it:
public MainWindow() {
InitializeComponent();
Loaded += MainWindow_Loaded;
Closed += MainWindow_Closed;
}
private Process process;
private void MainWindow_Closed(object sender, EventArgs e) {
// Log("WpfApp3.log", $"{DateTime.Now} Closed");
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
// Log("WpfApplication3.log", $"{DateTime.Now} Loaded");
process = new Process {
StartInfo = {
UseShellExecute = false,
// FileName = #"..\..\WpfApp2\bin\Debug\WpfApp2.exe",
FileName = #"..\..\CnslApp1\bin\Debug\CnslApp1.exe",
// FileName = #"..\..\WnFrmApp2\bin\Debug\WnFrmApp2.exe",
CreateNoWindow = true
}
};
process.Start();
var result = process.CloseMainWindow();
if (result) {
...
}
}
Then create three new projects; one for each of Console/Windows Forms/WPF. and enter correct path to the executable into 'FileName' paramter of the StartInfo. Then you can play with parameters to see how each will behave.
In my case, process.CloseMainWindow() did had no effect until was moved into another method because process was not started yet. But once moved into a button handler and executed it will terminate all three types (one can be used at the time with this example).
Sole exception was Console application when window was hidden.

C# Run a program with progressbar to compress listbox items

I would like to write a custom gui for a compressor.
How is it possible to run the Command Line Interface on all files added into listbox ?
Also how to display a progressbar displaying the current progress (not in % but at least which file is currently processing).
If you're talking about just running a command line program, you can use System.Diagnostic.Process.
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = #"c:\path\to\my.exe";
p.StartInfo.Arguments = #"c:\path\to\filetoCompress.file";
//event wireup
p.Exited += new EventHandler(p_exited);
p.Start();
As far as displaying progress for that, you could use the Exited event of the process to wire up to a process bar that shows the progress of number exted vs. number total.
void p_Exited(object sender, EventArgs e)
{
//assuming you have setup this bar previously.
pbFilesCommpressProgress.PerformStep();
}
In a CLI you can use one of many ASCII characters like ||| or ... and then you can append them as files progress.. or you can denote (file x of xxx), and inform the user of the progress as it occurs.

Starting an external process and setting a value after it finishes

I'm working on a WPF app which is set up to always be the topmost window. I've added a button to this app which launches an external program that allows the user to calibrate the touchscreen monitor our users will be interacting with.
I've can turn our mainwindow's topmost setting off and launch my app but I need to be able to set our MainWindow.Topmost to true after this external app exits.
It's been suggested that I add an event handler when starting the process that can reset topmost when the process ends. Event Handlers are new to me so I'm not sure how to do this. Can someone walk me through it?
Here's the code I have that currently disables topmost for my main window and launches my application. There's not much to it so far...
Application.Current.MainWindow.Topmost = false;
System.Diagnostics.Process.Start(#"C:\path\to\app.exe");
Many thanks.
(And I'll be reading up on event handlers and delegates this weekend!)
Create the Process, set EnableRaisingEvents to true and handle the Exited event:
Process p = new Process();
p.StartInfo.FileName = pathToApp;
p.EnableRaisingEvents = true;
p.Exited += OnCalibrationProcessExited; // hooks up your handler to the Process
p.Start();
// Now .NET will call this method when the process exits
private void OnCalibrationProcessExited(object sender, EventArgs e)
{
// set Topmost
}
From the comments thread, the Exited event gets raised on a worker thread, so you will need to do use Dispatcher.BeginInvoke to switch over to the UI thread to set Topmost:
private void OnCalibrationProcessExited(object sender, EventArgs e)
{
Action action = () => { /* set Topmost */ };
Dispatcher.BeginInvoke(DispatcherPriority.Normal, action);
}
(This assumes the code is in your Window class. If not, you will need to write something like Application.Current.MainWindow.Dispatcher.BeginInvoke(...) instead.)
Note I have separated creating and configuring the Process object from starting it. Although this is more verbose, it is necessary to ensure that all the event handling stuff is in place before the process starts -- otherwise the process could exit before you put the handler in place (unlikely, but theoretically possible!) and your handler would never get called.
You can wait for the process to exit via Process.WaitForExit:
Application.Current.MainWindow.Topmost = false;
var process = System.Diagnostics.Process.Start(#"C:\path\to\app.exe");
process.WaitForExit();
Application.Current.MainWindow.Topmost = true;
If you want to provide a timeout value to prevent the process from waiting forever, that is also possible. For example, if you wanted to wait for a maximum of 2 minutes, you could do:
process.WaitForExit(2 * 60000); // 60000ms/minute

Categories