How to queue up system process start - c#

I've written the following code to loop around a load of data table rows and generate a PDF if it doesn't already exist. It works, but it launches the wkhtmltoPDFs all in one go so 30 processes get started and kill the server, d'oh!
What's the best way to launch one process at a time and not start the second until the previous one has run?
DB db = new DB();
DataTable dtPosters = db.GetDataTable("select * from Invoices where PDFGenerated <> 1 or PDFGenerated is Null");
foreach (DataRow DR in dtPosters.Rows)
{
//Generate Poster, If exsists (Don't!)
Directory.CreateDirectory(string.Format("D:\\Invoices\\"));
string FilePath = string.Format("D:\\Invoices\\{0}.pdf", DR["InvoiceNumber"].ToString());
if (!File.Exists(FilePath))
{
string CMD = string.Format("C:\\Services\\Automafe\\wkhtmltoPDF.exe http://invoicegen/viewinvoice.aspx?InvoiceNumber={0} {1}", DR["InvoiceNumber"].ToString(), FilePath);
System.Diagnostics.Process.Start("cmd", "/c " + CMD);
}
else
{
//Update the DB
}
}

Process.Start returns a Process object, which lets you monitor the state of the newly-created process.
A simple, blocking way would be to have each worker wait for the process to exit
var myProcess = System.Diagnostics.Process.Start("cmd", "/c " + CMD);
myProcess.WaitForExit();
A better way would be to use the Exited event handler to monitor when the process exits.
var myProcess = System.Diagnostics.Process.Start("cmd", "/c " + CMD);
myProcess.Exited += myProcessFinishedHandler;

Related

how to catch command prompt process finish in C# and do something after that?

I am working with voice records. I need to use an .exe file for convert Wav to .mp3 file. Everything is fine I can execute this exe but I need to do something after when process end with my output .mp3 file. I know my output directory but i cant handle MP3 file before its not created yet. I know maybe I need to use Thread.sleep(); or something like that because I cant catch a file before its not exist.
Here is my code:
string mp3GuidName = Guid.NewGuid().ToString();
var mp3FilePath = WavFilePath.Replace("finalWavFile", mp3GuidName).Replace("wav", "mp3");
var extrasFilePath = HttpContext.Current.Server.MapPath("/").Replace("DevApp.Web", "Extras");
string strArguments = "/c start " + extrasFilePath + "lame.exe --abr 80 -V5 " + WavFilePath + " " + mp3FilePath;
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = strArguments ;
process.StartInfo = startInfo;
process.Start();
var attactment = new Attachment
{
CreatedOn = DateTime.Now,
UpdatedOn = DateTime.Now,
Title = mp3GuidName +".mp3",
Size = _storageProvider.GetFile(mp3FilePath).GetSize(), // here I am trying to get mp3 file but i cant catch it. Because if this wav files size is huge, then convert process is taking time and my mp3 file is not created yet.
FileExtension = _storageProvider.GetFile(mp3FilePath).GetFileType()
};
attactment.MimeType = _storageProvider.GetMimeType(attactment.FileExtension);
attactment.FileUrl = mp3GuidName+".mp3";// file.GetName();
attactment.AttachmentFolderId = folder.Id;
_attachmentRepository.Add(attactment);
I was try to use process.WaitForExit();but I cant solve this problem. I still cant acces to mp3 file.
so how can I catch when the process finish?
Best Regards.
Remove the start command argument from your argument string and you should be able to use process.WaitForExit(); to wait for Lame to finish with encoding:
string strArguments = "/c " + extrasFilePath + "lame.exe --abr 80 -V5 " + WavFilePath + " " + mp3FilePath;
However, you can simplify your code and avoid this dance with cmd.exe altogether by starting lame.exe directly:
string strArguments = "--abr 80 -V5 " + WavFilePath + " " + mp3FilePath;
...
startInfo.FileName = extrasFilePath + "lame.exe";
startInfo.Arguments = strArguments;
...
Below some information about why using the start command argument in your scenario is counterproductive.
Executing console applications such as lame.exe using cmd.exe (or from a console or batch file) normally block cmd.exe (or console/batch file) until the console application exits.
However, using the start command turns this normally blocking execution of a console application into a non-blocking execution. With this argument, the cmd.exe (or console/batch file) will continue execution while the console application is still running. In your particular case it means cmd.exe will exit right after it has started lame.exe (since it has nothing else to execute), effectively sabotaging your attempt to wait for lame.exe to finish.
Edited:
Base on the comments below I have to make it clear that the oroginal solution I recommended does not check if the file is free but it checks only if the file exists!
So I rather recommend the following:
private bool IsBusy(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
}
catch ()
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
return false;
}
the usage will be:
while(IsBusy(fileinfo))
{
//just wait
}
ORIGINAL:
You can use a while loop to find out when the file is ready:
while(!File.Exists(mp3FileName))
{
//just wait
}
// add the attachment here

System.Diagnostics.Process WaitForExit doesnt kill the process on timeout

I run 7-zip from my c# code:
ProcessStartInfo processStartInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = zipFileExePath,
Arguments = "x \"" + zipPath + "\" -o\"" + extractPath + "\""
};
using (Process process = Process.Start(processStartInfo))
{
if (process.WaitForExit(timeout))
{
}
else
{
s_logger.ErrorFormat("Timeout whilte extracting extracting {0}", zipPath);
}
process.Close();
}
Now what I see happening is that when the timeout hits, still the 7-zip process exists in Task Manager. Why is that happening? I put both close and dispose
Your question mentions three methods on the Process class:
WaitForExit
Close
Dispose
None of those methods will do anything to the process, certainly not kill it.
WaitForExit is an observational method, it will wait and see if the process terminates by itself. The overload with the timeout will return a bool telling you whether the method observed that the process terminated or not. If it didn't, it's presumably still running.
Close and Dispose does nothing to or for the process that is running, it merely closes the handle you have internally in the Process class that is the mechanism for how that class can keep tabs of the process in question.
It's a good idea to close this handle when you're done observing the running process.
However, if you want the process to terminate, you will have to call Process.Kill.
Maybe something like the following:
ProcessStartInfo processStartInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = zipFileExePath,
Arguments = "x \"" + zipPath + "\" -o\"" + extractPath + "\""
};
using (Process process = Process.Start(processStartInfo))
{
if (process.WaitForExit(timeout))
{
//somecode?
}
else
{
s_logger.ErrorFormat("Timeout whilte extracting extracting {0}", zipPath);
}
process.Kill();
}

Print PDF file using Foxit Reader and C#

My program prints silently via the PDF reader Foxit Reader in a new process.
On occasion, my program attempts to print two PDFs at the same time, which causes one of them to fail to print.
Here is my code:
string filename = "file.pdf";
string fileDir1 = #"C:\Program Files (x86)\Foxit Software\Foxit Reader\FoxitReader.exe";
Process pdfProcess = new Process();
pdfProcess.StartInfo.FileName = fileDir1;
pdfProcess.StartInfo.Arguments = string.Format(#"/t {0} {1}", filename ,"pos-80");
pdfProcess.StartInfo.CreateNoWindow = true;
pdfProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(fileDir1);
pdfProcess.Start();
if (!pdfProcess.WaitForExit(2500))
{
pdfProcess.Kill();
}
Please help me resolve this issue.
Make sure you have Foxit open.
using System.Diagnostics;
List<Process> Processlist = Process.GetProcesses().ToList();
This gives you a list of currently running processes.
foreach(Process p in Processlist)
{
Console.WriteLine("Process " + p.Id + " is named '" + p.ProcessName + "'");
}
When running the above code, you should see the name of the Foxit process in your output window.
Alternatively, put a break-point on the foreach line and hover over the list to see all the names that way.
bool IsFoxitProcessRunning = false;
foreach(Process p in Processlist)
{
if(p.ProcessName == "Foxit process name here") //Replace with the name of the foxit process
{
IsFoxitProcessRunning = true;
}
}
Now, only start a new Foxit process if one isn't already running.
if(!IsFoxitProcessRunning)
{
//insert code to run next foxit process here.
}
Notes:
You may need to implement a queue to keep track of pdfs waiting to run.
You may also wish to alert IT support if a Foxit is waiting more 5 or 10 mins to run.
You could choose to make Processlist a class attribute, and periodically refresh Processlist using a Timer, by calling Processlist = Process.GetProcesses().ToList(); on the Tick event. every 30 seconds or so while a PDF is waiting to be printed.

Kill Certain MSTSC Process

Is there a way to kill certain instances of the mstsc process.
For example, I rdp to pc1.xyz.com.au and pc2.xyz.com.au.
Now from c#, I want to kill or disconnect pc1.xyz.com.au.
Currently the code below kills all the instances of mstsc process.
Is there any way I can disconnect only certain mstsc instances.
private void terminateRDP()
{
foreach (var process in Process.GetProcessesByName("mstsc"))
{
process.Kill();
}
}
I tried saving the pid of the process that is opened but the capture pid that i captured is different than the one in the task bar. I am opening a .rdp file using code below.
Process rdcProcess = new Process();
rdcProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\cmdkey.exe");
rdcProcess.StartInfo.Arguments = "/generic:TERMSRV/" + server + " /user:" + username + " /pass:" + password;
rdcProcess.Start();
rdcProcess.WaitForExit();
changeServerRDP(serverAddress);
if (getApplicationPath(serverList.SelectedItem.ToString()) != String.Empty)
{
changeServerRDPPath(getApplicationPath(serverList.SelectedItem.ToString()));
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\mstsc.exe");
rdcProcess.StartInfo.Arguments = "C:\\rdp\\my.rdp";
rdcProcess.Start();
rdcProcess.WaitForExit();
//pids.Add(rdcProcess.Id);
//int procID = rdcProcess.Id;
//MessageBox.Show(procID.ToString());
//opened.Add(rdcProcess);
}
If you need to terminate RDP session, You can try: WTSDisconnectSession API
This stackoverflow link explains how to use it in C#

C# Cannot Delete File - System.UnauthorizedAccessException

I am running a separate process that minimizes a folder of javascript files. This process creates a new file for each of the js files with "_min.js" appended to it. The next step is to delete the old js files (the ones without "_min.js"). For some reason File.Delete cannot delete these files.
It would appear that some process still has a handle on these files. I get a System.UnauthorizedAccessException exception when I attempt the delete. I have sufficient privileges to this folder. Can someone tell me what I am overlooking?
I am running the process several times in this loop.
foreach (var fileInfo in jsFiles)
{
var outFileName = fileInfo.FullName.Replace(".js", "_min.js");
var compressorPath = "\"C:\\Dev\\Team Interactive Tools\\trunk\\Infrastructure\\MsBuild\\lib\\yuicompressor-2.4.2.jar\"";
StringBuilder stringBuilder = new StringBuilder("-jar " + compressorPath + " ");
stringBuilder.Append("\"" + fileInfo.FullName + "\"");
stringBuilder.Append(" -o " + "\"" + outFileName + "\"");
Process p = new Process();
p.StartInfo.FileName = "\"C:\\Program Files (x86)\\Java\\jre6\\bin\\java\"";
p.StartInfo.Arguments = stringBuilder.ToString();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
}
return true;
}
Then I try to remove the orginals:
private void RemoveOrginalJs(FileInfo[] files)
{
foreach (var fileInfo in files)
{
File.Delete(fileInfo.FullName);
}
}
I am tried Process.close() after each process run but it makes no differance.
I don't know the tool that you are starting, but waiting for its completion somehow seems the right thing to do:
p.Start();
p.WaitForExit();
Maybe the threads still have the file locked? Do you wait for them to finish before you try and delete?
Try Process.Kill() and delete afterwards.
Further you have to check if the script isn't running in another process aswell. To determinate this, try using Unlocker.

Categories

Resources