[.NET,iTextSharp]用程式呼叫cmd(command line)執行exe(以開啟adobe reader列印pdf為例)
要透過程式碼呼叫adobe reader來列印pdf的話,比較簡單明瞭的方式就是透過command line來呼叫,呼叫command line列印的方式有兩種,一種是呼叫之後,command line會自動關閉,另外一種則是呼叫之後,command line還是開啟著。
本篇的adobe reader版本是11.0,作業系統環境是windows 8 64bit,如果是用其他版本的adobe reader或是其他版本的windows,請自行修改路徑喔!
1.執行之後會跳出cmd視窗,但是穩定性高,幾乎可以執行所有種類的外部.exe,透過Process.StandardInput.WriteLine()直接下你要執行的.exe + filename即可。
如果要解決跳出cmd視窗的問題的話,建議可以用console執行這段程式碼然後透過排程管理員執行console就OK了,就不會跳出cmd視窗。
想要透過設定Process的參數,讓cmd視窗不會跳出來的話,試了很久都沒成功,目前推測是不可能的,推測可能是StandardInput.WriteLine()導致強制跳出cmd視窗。
首先要先取得adobe reader的安裝路徑,主要是透過.net的Registry物件,細節請看下面程式碼片段:
var adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Classes").OpenSubKey("acrobat").OpenSubKey("shell").OpenSubKey("open").OpenSubKey("command");
string adobeExeFileName = adobe.GetValue("").ToString();
adobeExeFileName = adobeExeFileName.Substring(1, adobeExeFileName.IndexOf(".exe") + 3);
然後用Process.StandardInput.WriteLine()直接執行:
var processStartInfo = new ProcessStartInfo();
processStartInfo.WorkingDirectory = Path.GetDirectoryName(adobeExeFileName);
processStartInfo.FileName = "cmd.exe";
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.UseShellExecute = false;
// set additional properties
Process proc = Process.Start(processStartInfo);
proc.StandardInput.WriteLine(Path.GetFileName(adobeExeFileName) + " /p " + pdfFileName);
proc.Close();
會自動跳出列印pdf的視窗:
參考的完整程式碼:
private void PrintToPrinterBtn_Click(object sender, EventArgs e)
{
Document doc = new Document(PageSize.A8);
string pdfFileName = Application.StartupPath + "\\test.pdf";
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(pdfFileName, FileMode.Create));
doc.Open();
doc.Add(new Paragraph("when open this pdf, the printer will start to print!!!"));
doc.Close();
//這是會跳出commandline視窗的方式,但是非常穩定(因為是StandardInput.WriteLine的關係,但也一定會跳出cmd視窗),就算phantomjs也能透過這種指令執行
//如果要解決跳出cmd視窗的問題的話,建議可以用console執行這段程式碼然後透過排程管理員執行就OK了,就不會跳出cmd視窗
var adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Classes").OpenSubKey("acrobat").OpenSubKey("shell").OpenSubKey("open").OpenSubKey("command");
string adobeExeFileName = adobe.GetValue("").ToString();
adobeExeFileName = adobeExeFileName.Substring(1, adobeExeFileName.IndexOf(".exe") + 3);
//設定cmd參數
var processStartInfo = new ProcessStartInfo();
processStartInfo.WorkingDirectory = Path.GetDirectoryName(adobeExeFileName);
processStartInfo.FileName = "cmd.exe";
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.UseShellExecute = false;
//開始執行
Process proc = Process.Start(processStartInfo);
proc.StandardInput.WriteLine(Path.GetFileName(adobeExeFileName) + " /p " + pdfFileName);
proc.Close();
MessageBox.Show("已完成");
}
2.列印時不會跳出cmd視窗寫法:
一樣是透過Process物件執行cmd指令,差別就在於會設定Process.StartInfo.WindowStyle的屬性為隱藏cmd視窗的彈出。相信在絕大多數的情況下,大部分人會選擇這個隱藏跳出cmd視窗的作法拉,但是實際測試真的有碰到不支援的.exe的情況(ex:PhantomJS),所以姑且叫這個作法的穩定性為80%吧!
Process pdfProcess = new Process();
pdfProcess.StartInfo = newProcess;
//在此隱藏執行視窗
pdfProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pdfProcess.Start();
pdfProcess.Close();
執行結果跟上面相同,就不重複貼了。
完整程式碼:
private void PrintToPrinterHideBtn_Click(object sender, EventArgs e)
{
Document doc = new Document(PageSize.A8);
string pdfFileName = Application.StartupPath + "\\test.pdf";
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(pdfFileName, FileMode.Create));
doc.Open();
doc.Add(new Paragraph("when open this pdf, the printer will start to print!!!"));
doc.Close();
//這是隱藏command line視窗的方式,曾經碰過.exe無法這樣執行的,ex:Phantomjs
//透過Registry取得adobe reader的安裝路徑
var adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Classes").OpenSubKey("acrobat").OpenSubKey("shell").OpenSubKey("open").OpenSubKey("command");
string adobeExeFileName = adobe.GetValue("").ToString();
adobeExeFileName = adobeExeFileName.Substring(1, adobeExeFileName.IndexOf(".exe") + 3);
ProcessStartInfo newProcess = new ProcessStartInfo("\"" + adobeExeFileName + "\"", " /p \"" + pdfFileName + "\"");
newProcess.CreateNoWindow = true;
newProcess.RedirectStandardOutput = true;
newProcess.UseShellExecute = false;
Process pdfProcess = new Process();
pdfProcess.StartInfo = newProcess;
//在此隱藏執行視窗
pdfProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pdfProcess.Start();
pdfProcess.Close();
MessageBox.Show("已完成");
}
要注意的地方就是,不論使用上列哪一種寫法,最後釋放資源的時候最好使用Process.Close(),而不要用Process.WaitForExit(),如果印表機剛好當掉的話,就會把原本執行的應用程式(webform or winform)給block住,然後你的應用程式就死當不能動囉~
美中不足的地方就是,還是會產出pdf檔案而且不能當下執行完立刻刪除,以及列印完畢之後,adobe reader仍然是開啟著的(但是剛才列印的檔案已關閉)。
這篇大概是這樣。。。
參考資料:
Can you print a pdf file using ITextSharp (c#) ? If yes how?