I'm currently working on a program that converts a list of files from .ps (PostScript) to .png.
Originally, this was done in a batch file, one file at a time. I am working on code that uses the Ghostscript.NET dll to process these files asynchronously. By splitting these up into tasks, I have cut down the processing time from 30 minutes to about 6 minutes.
I want to be able to show the user some sort of progress on this, so that it doesn't just look like my program is frozen.
I know just enough about threading to frustrate myself, so any suggestions on the best way to do this is greatly appreciated. The code below has a BackgroundWorker implemented to try to show the progress. I have used BGWorker before to show progress, but not on multiple tasks like this. In fact, this is my first time multi-threading without just using BGWorker.
I feel that BGWorker is probably not what I need to be using, but I wanted to try to take a stab at it myself before I asked.
Here is the code that I have so far:
public partial class ProcessStatusForm : Form
{
public string[] testList;
public string wordPath;
public string StatusText;
public GhostscriptVersionInfo _gs_version_info;
public DirectoryInfo dInfo;
public List<Task> tasks;
public float NumberOfTasks;
public bool PS2PNGRunning;
public int ProgressPct;
public float dPercent;
public decimal decPercent;
public ProcessStatusForm(string wordDoc, List<string> runList)
{
InitializeComponent();
this.wordPath = wordDoc;
this.testList = runList.ToArray();
this.StatusText = string.Empty;
this._gs_version_info = GhostscriptVersionInfo.GetLastInstalledVersion(GhostscriptLicense.GPL |
GhostscriptLicense.AFPL, GhostscriptLicense.GPL);
this.dInfo = new DirectoryInfo(SettingsClass.PSFolder);
this.PS2PNGRunning = false;
this.ProgressPct = 0;
this.NumberOfTasks = runList.Count;
}
private void ProcessStatusForm_Shown(object sender, EventArgs e)
{
//Spawn tasks for each of the .ps files in the PS_FILES folder
tasks = new List<Task>(dInfo.GetFiles("*.ps").Length);
//Start the BackgroundWorker
this.PS2PNGRunning = true;
BackgroundWorker.RunWorkerAsync();
foreach (var file in dInfo.GetFiles("*.ps"))
{
//Get fileName to pass fo the ConvertPS2PNG
string inputFile = file.Name;
//Create the Task
var task = Task.Factory.StartNew(() => ConvertPS2PNG(inputFile));
tasks.Add(task);
}
//Wait until all tasks have completed
Task.WaitAll(tasks.ToArray());
PS2PNGRunning = false;
}
private void ConvertPS2PNG(string input)
{
string output = input.Replace(".ps", "_01.png");
input = SettingsClass.PSFolder + input;
output = SettingsClass.PNGFolder + output;
GhostscriptProcessor processor = new GhostscriptProcessor(_gs_version_info, true);
processor.Process(CreateGSArgs(input, output), new ConsoleStdIO(true, true, true));
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
ProgressPct = 0;
while (PS2PNGRunning)
{
Thread.Sleep(1000);
float TasksCompleted = 0;
foreach (var tsk in tasks)
{
if (tsk.Status == TaskStatus.RanToCompletion)
{
TasksCompleted++;
}
}
StatusText = TasksCompleted + " of " + NumberOfTasks + " converted...";
dPercent = TasksCompleted / NumberOfTasks;
dPercent *= 100;
decPercent = (decimal)dPercent;
decPercent = Math.Round(decPercent);
ProgressPct = (int)decPercent;
BackgroundWorker.ReportProgress(ProgressPct);
}
BackgroundWorker.ReportProgress(100);
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ProgressLabel.Text = this.StatusText;
this.progressBar.Style = ProgressBarStyle.Continuous;
this.progressBar.Value = e.ProgressPercentage;
}
public string[] CreateGSArgs(string inPath, string outPath)
{
List<string> gsArgs = new List<string>();
gsArgs.Add("-dBATCH");
gsArgs.Add("-dNOPAUSE");
gsArgs.Add("-sDEVICE=png16m");
gsArgs.Add("-dQUIET");
gsArgs.Add("-sPAPERSIZE=letter");
gsArgs.Add("-r800");
gsArgs.Add("-sOutputFile=" + outPath);
gsArgs.Add(inPath);
return gsArgs.ToArray();
}
}
When I put breaks in the code of BackgroundWorker_DoWork, everything seems to be coming out right, but when it gets to the BackgroundWorker.ReportProgress(), it never makes it to the BackgroundWorker_ProgressChanged() method.
At the very least, I could live with just having a progressBar.Style as marquee while this is running so that the user can see that the program is working, but reporting the actual progress would be ideal.
As I said before, I haven't done a ton of work with threading, and all of my knowledge on the subject pretty much comes from Google and StackOverflow. If there is a completely different way to do this, I am open to all criticism.