C# Run a program with progressbar to compress listbox items - c#

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.

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.

Synchronization between two processes in 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
}

How to monitor a process that launches "dllhost.exe"?

updated
I have a problem related to Process.Start();
My program launches files as processes, like so:
Process processMonitor = new Process();
processMonitor.StartInfo.FileName = filePath; // Example: #"C:\test.txt"
processMonitor.StartInfo.CreateNoWindow = true;
processMonitor.Exited += new EventHandler(Process_Exited);
processMonitor.EnableRaisingEvents = true;
processMonitor.Start();
// Handle Exited event and display process information.
private void Process_Exited(object sender, EventArgs e)
{
// This code is called on every exit, except images: (Windows Photo Viewer, *jpg, *png, *bmp etc.)
}
This successfully launches a process, notepad.exe with the correct file.
Catching the Exited event also works so basically i have everything in place to monitor the close event for the process.
Now for the problem...
When doing exactly the same, but now for an image:
processMonitor.StartInfo.FileName = filePath; // Example: #"C:\test.jpg"
This is not successfull.. The process launches perfectly, But i can not detect if the process is ever closed. A little research shows me that a process called:
DLLHOST.EXE (COM Surrogate)
Is launched and i cannot detect the Exited event for this process.
Can anybody help me, or at least point me in the right direction?
If all other doesn't work, you can look into WMI: http://msdn.microsoft.com/en-us/library/aa394582(v=vs.85).aspx - this will require you to do some wrapping work (or use a wrapper, like the one here: http://www.codeproject.com/Articles/21971/WMI-Interface-for-NET)
Another option you can use as last resort and as a workaround only is polling for the process state, but this is really not recommended for most project, and it certainly doesn't sound like something you want to do in your project.
I think it has to do with the nature of an image. Opening a .txt file launches notepad whereas opening a .jpg opens a viewer. Any way to key into the viewer itself?

Asynchronous capture from a process output not working properly [duplicate]

This question already has answers here:
C equivalent of autoflush (flush stdout after each write)?
(3 answers)
Closed 3 years ago.
I'm developing a control for a website, where user can upload his PDF, and after the upload a 3rd party CLI-tool launches to verify PDF against certain profile and generate a corresponding report.
The tool mentioned is callas pdfToolbox 4 (available here http://www.callassoftware.com/callas/doku.php/en:download[^])
The problem is that on my control at the website I need to display in real-time progress bar of checking the PDF-file. All the AJAX-stuff for this functionality is already written (ajax-postbacks, updates of progress-bar, etc), but there's a problem with asynchronous updates from the process, which launches the pdf-checking tool.
If you launch the tool from command-line window, you can see that, it generates output into standard output stream, which contains progress updates (in percents), as well as possible messages about errors in the PDF-file.
However, if the tool is launched by the process which I create in my web-control, I don't receive the OutputDataReceived events until the check has been finished, and then many OutputDataReceived events come at once, one after one.
My code is the following (I've written a small console-app to test things faster):
class Program
{
static string appString = "path-to-callas-cli";
static string argString = "path-to-pdf-and-path-to-report-and-path-to-callas-profile";
static void Main(string[] args)
{
ProcessStartInfo pInfo = new ProcessStartInfo(appString, argString);
pInfo.UseShellExecute = false;
pInfo.CreateNoWindow = true;
pInfo.RedirectStandardOutput = true;
pInfo.RedirectStandardError = true;
pInfo.RedirectStandardInput = true;
pInfo.ErrorDialog = true;
Process process = new Process();
process.StartInfo = pInfo;
process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
process.Exited += new EventHandler(process_Exited);
process.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
Console.ReadKey();
}
static void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
}
static void process_Exited(object sender, EventArgs e)
{
}
static void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Received async output: " + e.Data);
}
}
As I've said, all the output from Callas CLI comes at once in the end (while the check takes about 35 seconds). To test my own code, I've created a small console app, which outputs numbers 10-20-30-....-100 in 500 milli-second intervals, and it's output is displayed perfectly from the main app, coming with 500ms intervals.
Any ideas?
I've had the exact same problem, Calling a CLI app from C# .NET from which I needed to get realtime stdOut updates (progress report of an archiver), but it didn't send any output until after the process exited (Not helpful to get a progress report after 10 minutes of compressing)
From what I understand it is the process's fault, not flushing the stdOut buffer. I couldn't find any way on .Net to manually tell the process to flush its stdOut. However, I found a hacky solution to be able to read the stdOut in realtime.
All I did was access the Process.StandardOutput.BaseStream.ReadByte() method which does work and returns actual bytes sent to the stdOut. This is pure data including carriage manipulation etc.
Then convert the byte (seems to be ASCII?) to a character with Char.ConvertFromUtf32(..) and push the character into a stringBuilder object. And now, since I have stdOut data, I can deal with it however I want.
Example: For my case, I wanted to capture the stdOut word by word and then callback to user to handle each word.
// - Standard process
proc = new Process();
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.filename = "...";
proc.start();
// - Init some things
int byte_r; // The byte that is going to be read from stdOut
StringBuilder word = new StringBuilder(); // Append the characters here
Action<String> onStdOutWord; // USERSET from before. Callbacks words read from stdOut
// As long as there is stdOut Data
while( (byte_r = proc.StandardOutput.BaseStream.ReadByte()) > -1 )
{
// If SPACE or ENTER callback the current word
if(byte_r==32 || byte_r==13) {
if(word.Length>0) {
onStdOutWord(word.ToString());
word.Clear();
}
}else{
// Append character to string, skip special characters
if(byte_r>32) {
word.Append(Char.ConvertFromUtf32(byte_r));
}
}//-
}// - end while
Then, using the custom callback onStdOutWord() I was getting realtime data from the CLI app and handled it to get what I wanted.
The above is code just a use case since I wanted to get words, you can alter it and have it work like however you want. e.g. Not splitting into words and pushing out the entire stringBuilder object?
I know it's 8 years after the original question here, but I spend too much time researching on why I couldn't get stdout data like the OP, and figured to share my solution in case anyone else has the same problem and stumbles upon this page, like I did 😌

Categories