C#的Process類調(diào)用第三方插件實(shí)現(xiàn)PDF文件轉(zhuǎn)SWF文件
在項(xiàng)目開發(fā)過(guò)程中,有時(shí)會(huì)需要用到調(diào)用第三方程序?qū)崿F(xiàn)本系統(tǒng)的某一些功能,例如本文中需要使用到的swftools插件,那么如何在程序中使用這個(gè)插件,并且該插件是如何將PDF文件轉(zhuǎn)化為SWF文件的呢?接下來(lái)就會(huì)做一個(gè)簡(jiǎn)單的介紹。
在.NET平臺(tái)中,對(duì)C#提供了一個(gè)操作對(duì)本地和遠(yuǎn)程的訪問進(jìn)程,使能夠啟動(dòng)和停止系統(tǒng)進(jìn)程。這個(gè)類就是System.Diagnostics.Process,我們首先來(lái)了解一下該類。
一.解析System.Diagnostics.Process類
在C#中使用Process類可以提供對(duì)本地和遠(yuǎn)程的訪問進(jìn)程,使能夠啟動(dòng)和停止系統(tǒng)進(jìn)程,并且該類可以對(duì)系統(tǒng)進(jìn)程進(jìn)行管理。該類中的一些常用方法:Start() ,Kill(),WaitForExit()等方法;StartInfo,F(xiàn)ileName,CreateNoWindow等屬性。
1.Start()方法:?jiǎn)?dòng)(或重用)此 Process 組件的 StartInfo 屬性指定的進(jìn)程資源,并將其與該組件關(guān)聯(lián)。如果啟動(dòng)了進(jìn)程資源,則為 true;如果沒有啟動(dòng)新的進(jìn)程資源(例如,如果重用了現(xiàn)有進(jìn)程),則為 false。
具體介紹一下該方法的實(shí)現(xiàn)代碼:
/// <devdoc> /// <para> /// <see cref='System.Diagnostics.Process'/>如果過(guò)程資源被重用而不是啟動(dòng),重用的進(jìn)程與此相關(guān)聯(lián)<see cref ='System.Diagnostics.Process'/>零件。 /// </para> /// </devdoc> [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public bool Start() { Close(); ProcessStartInfo startInfo = StartInfo; if (startInfo.FileName.Length == 0) throw new InvalidOperationException(SR.GetString(SR.FileNameMissing)); if (startInfo.UseShellExecute) { #if !FEATURE_PAL return StartWithShellExecuteEx(startInfo); #else throw new InvalidOperationException(SR.GetString(SR.net_perm_invalid_val, "StartInfo.UseShellExecute", true)); #endif // !FEATURE_PAL } else { return StartWithCreateProcess(startInfo); } }
2.Kill()方法:立即停止關(guān)聯(lián)的進(jìn)程。Kill 強(qiáng)制終止進(jìn)程,Kill 方法將異步執(zhí)行。 在調(diào)用 Kill 方法后,請(qǐng)調(diào)用 WaitForExit 方法等待進(jìn)程退出,或者檢查 HasExited 屬性以確定進(jìn)程是否已經(jīng)退出。
具體介紹一下該方法的實(shí)現(xiàn)代碼:
[ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public void Kill() { SafeProcessHandle handle = null; try { handle = GetProcessHandle(NativeMethods.PROCESS_TERMINATE); if (!NativeMethods.TerminateProcess(handle, -1)) throw new Win32Exception(); } finally { ReleaseProcessHandle(handle); } }
SafeProcessHandle GetProcessHandle(int access) { return GetProcessHandle(access, true); } /// <devdoc> /// 獲取進(jìn)程的短期句柄,具有給定的訪問權(quán)限。 ///如果句柄存儲(chǔ)在當(dāng)前進(jìn)程對(duì)象中,則使用它。 ///注意,我們存儲(chǔ)在當(dāng)前進(jìn)程對(duì)象中的句柄將具有我們需要的所有訪問權(quán)限。 /// </devdoc> /// <internalonly/> [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] SafeProcessHandle GetProcessHandle(int access, bool throwIfExited) { Debug.WriteLineIf(processTracing.TraceVerbose, "GetProcessHandle(access = 0x" + access.ToString("X8", CultureInfo.InvariantCulture) + ", throwIfExited = " + throwIfExited + ")"); #if DEBUG if (processTracing.TraceVerbose) { StackFrame calledFrom = new StackTrace(true).GetFrame(0); Debug.WriteLine(" called from " + calledFrom.GetFileName() + ", line " + calledFrom.GetFileLineNumber()); } #endif if (haveProcessHandle) { if (throwIfExited) { //因?yàn)閔asProcessHandle是true,我們知道我們有進(jìn)程句柄 //打開時(shí)至少要有SYNCHRONIZE訪問,所以我們可以等待它 // zero timeout以查看進(jìn)程是否已退出。 ProcessWaitHandle waitHandle = null; try { waitHandle = new ProcessWaitHandle(m_processHandle); if (waitHandle.WaitOne(0, false)) { if (haveProcessId) throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture))); else throw new InvalidOperationException(SR.GetString(SR.ProcessHasExitedNoId)); } } finally { if( waitHandle != null) { waitHandle.Close(); } } } return m_processHandle; } else { EnsureState(State.HaveId | State.IsLocal); SafeProcessHandle handle = SafeProcessHandle.InvalidHandle; #if !FEATURE_PAL handle = ProcessManager.OpenProcess(processId, access, throwIfExited); #else IntPtr pseudohandle = NativeMethods.GetCurrentProcess(); // Get a real handle if (!NativeMethods.DuplicateHandle (new HandleRef(this, pseudohandle), new HandleRef(this, pseudohandle), new HandleRef(this, pseudohandle), out handle, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS | NativeMethods.DUPLICATE_CLOSE_SOURCE)) { throw new Win32Exception(); } #endif // !FEATURE_PAL if (throwIfExited && (access & NativeMethods.PROCESS_QUERY_INFORMATION) != 0) { if (NativeMethods.GetExitCodeProcess(handle, out exitCode) && exitCode != NativeMethods.STILL_ACTIVE) { throw new InvalidOperationException(SR.GetString(SR.ProcessHasExited, processId.ToString(CultureInfo.CurrentCulture))); } } return handle; } }
3.WaitForExit()方法:指示<see cref ='System.Diagnostics.Process'/>組件等待指定的毫秒數(shù),以使相關(guān)聯(lián)的進(jìn)程退出。
具體介紹一下該方法的實(shí)現(xiàn)代碼:
public bool WaitForExit(int milliseconds) { SafeProcessHandle handle = null; bool exited; ProcessWaitHandle processWaitHandle = null; try { handle = GetProcessHandle(NativeMethods.SYNCHRONIZE, false); if (handle.IsInvalid) { exited = true; } else { processWaitHandle = new ProcessWaitHandle(handle); if( processWaitHandle.WaitOne(milliseconds, false)) { exited = true; signaled = true; } else { exited = false; signaled = false; } } } finally { if( processWaitHandle != null) { processWaitHandle.Close(); } // If we have a hard timeout, we cannot wait for the streams if( output != null && milliseconds == -1) { output.WaitUtilEOF(); } if( error != null && milliseconds == -1) { error.WaitUtilEOF(); } ReleaseProcessHandle(handle); } if (exited && watchForExit) { RaiseOnExited(); } return exited; }
internal ProcessWaitHandle( SafeProcessHandle processHandle): base() { SafeWaitHandle waitHandle = null; bool succeeded = NativeMethods.DuplicateHandle( new HandleRef(this, NativeMethods.GetCurrentProcess()), processHandle, new HandleRef(this, NativeMethods.GetCurrentProcess()), out waitHandle, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS); if (!succeeded) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } this.SafeWaitHandle = waitHandle; }
4.StartInfo屬性:獲取或設(shè)置要傳遞給 Process 的 Start 方法的屬性。StartInfo 表示用于啟動(dòng)進(jìn)程的一組參數(shù)。 調(diào)用 Start 時(shí),StartInfo 用于指定要啟動(dòng)的進(jìn)程。 唯一必須設(shè)置的 StartInfo 成員是 FileName 屬性。
具體介紹一下該方法的實(shí)現(xiàn)代碼:
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MonitoringDescription(SR.ProcessStartInfo)] public ProcessStartInfo StartInfo { get { if (startInfo == null) { startInfo = new ProcessStartInfo(this); } return startInfo; } [ResourceExposure(ResourceScope.Machine)] set { if (value == null) { throw new ArgumentNullException("value"); } startInfo = value; } }
5.CreateNoWindow屬性:獲取或設(shè)置指示是否在新窗口中啟動(dòng)該進(jìn)程的值。
具體介紹一下該方法的實(shí)現(xiàn)代碼:
[ DefaultValue(false), MonitoringDescription(SR.ProcessCreateNoWindow), NotifyParentProperty(true) ] public bool CreateNoWindow { get { return createNoWindow; } set { createNoWindow = value; } }
以上簡(jiǎn)單介紹了該類的三種常用方法和兩種常用屬性,在實(shí)際的開發(fā)項(xiàng)目中無(wú)須對(duì)每個(gè)屬性方法和屬性的底層實(shí)現(xiàn)做全面的了解,但建議在學(xué)習(xí)該類的時(shí)候,適當(dāng)?shù)牧私庖幌履骋恍╊惖姆椒▽?shí)現(xiàn),有助于我們很好的掌握該類。
二.如何實(shí)現(xiàn)PDF文件轉(zhuǎn)化為SWF文件
在項(xiàng)目如果需要將PDF文件轉(zhuǎn)換為SWF文件,可以在項(xiàng)目中引入Swftools插件,該插件的主要功能:PDF到SWF轉(zhuǎn)換器。 每頁(yè)生成一幀。 使您能夠在Flash Movie中擁有完全格式化的文本,包括表格,公式,圖形等。 它基于Derek B. Noonburg的xpdf PDF解析器。
簡(jiǎn)單介紹一下該插件的常用參數(shù):
-h , –help Print short help message and exit 打印幫助信息
-V , –version Print version info and exit 打印版本號(hào)
-o , –output file.swf Direct output to file.swf. If file.swf contains ‘13568621′ (file13568630.swf), then each page指定輸出的swf文件名
-P , –password password Use password for deciphering the pdf.指定打開pdf的密碼
-z , –zlib Use Flash 6 (MX) zlib compression.使用Flash 6的zlib壓縮機(jī)制
-i , –ignore Allows pdf2swf to change the draw order of the pdf. This may make the generated允許程序修改pdf的繪制順序,可能會(huì)導(dǎo)致結(jié)果與原來(lái)有差異
以上是幾種常用的參數(shù),具體擦參數(shù)列表詳見:http://www.swftools.org/。
對(duì)實(shí)現(xiàn)本次操作的類和插件做了一個(gè)簡(jiǎn)單的介紹,接下來(lái)提供一個(gè)具體實(shí)現(xiàn)該功能的操作方法:
/// <summary> /// PDF格式轉(zhuǎn)為SWF /// </summary> /// <param name="pdfPathParameter">原視頻文件地址,如/a/b/c.pdf</param> /// <param name="swfPathParameter">生成后的FLV文件地址,如/a/b/c.swf</param> /// <param name="beginpage">轉(zhuǎn)換開始頁(yè)</param> /// <param name="endpage">轉(zhuǎn)換結(jié)束頁(yè)</param> /// <param name="photoQuality">照片質(zhì)量</param> /// <returns></returns> public static bool PdfConversionSwf(string pdfPathParameter, string swfPathParameter, int beginpage, int endpage, int photoQuality) { if (string.IsNullOrEmpty(pdfPathParameter)) { throw new ArgumentNullException(pdfPathParameter); } if (string.IsNullOrEmpty(swfPathParameter)) { throw new ArgumentNullException(swfPathParameter); } if (endpage < beginpage) { throw new ArgumentException("起始頁(yè)數(shù)大于結(jié)束頁(yè)數(shù)"); } if (photoQuality <= 0) { throw new ArgumentException("照片質(zhì)量錯(cuò)誤"); } var exe = HttpContext.Current.Server.MapPath("~/tools/swftools-2013-04-09-1007.exe"); var pdfPath = HttpContext.Current.Server.MapPath(pdfPathParameter); var swfPath = HttpContext.Current.Server.MapPath(swfPathParameter); Process p = null; try { if (!File.Exists(exe) || !File.Exists(pdfPath)) { return false; } if (File.Exists(swfPath)) { File.Delete(swfPath); } var sb = new StringBuilder(); sb.Append(" \"" + pdfPath + "\""); sb.Append(" -o \"" + swfPath + "\""); sb.Append(" -s flashversion=9"); sb.Append(" -s disablelinks"); if (endpage > GetPageCount(pdfPath)) { endpage = GetPageCount(pdfPath); } sb.Append(" -p " + "\"" + beginpage + "" + "-" + endpage + "\""); //SWF中的圖片質(zhì)量 sb.Append(" -j " + photoQuality); var command = sb.ToString(); //Process提供對(duì)本地和遠(yuǎn)程的訪問進(jìn)程,使能夠啟動(dòng)和停止系統(tǒng)進(jìn)程。 p = new Process { StartInfo = { FileName = exe, Arguments = command, WorkingDirectory = HttpContext.Current.Server.MapPath("~/Bin/"), UseShellExecute = false, RedirectStandardError = true, CreateNoWindow = false } }; //啟動(dòng)線程 p.Start(); //開始異步讀取 p.BeginErrorReadLine(); //等待完成 p.WaitForExit(); //開始同步讀取 //p.StandardError.ReadToEnd(); if (!File.Exists(swfPath)) return false; return true; } catch (IOException ioex) { throw new IOException(ioex.Message); } catch (Exception ex) { throw new Exception(ex.Message); } finally { if (p != null) { //關(guān)閉進(jìn)程 p.Close(); //釋放資源 p.Dispose(); } } }
三.小結(jié)
在本文中介紹了在C#中如何操作外部程序和線程的類System.Diagnostics.Process,并介紹了該類的一些常用方法的底層實(shí)現(xiàn)代碼,如果需要對(duì)該類進(jìn)行詳細(xì)的了解,可以根據(jù)MSDN和.NET底層源碼的相關(guān)注釋和文章進(jìn)行細(xì)致的學(xué)習(xí)。在介紹完實(shí)現(xiàn)操作的類的同時(shí),也對(duì)Swftools插件做了一個(gè)說(shuō)明,并列舉了相關(guān)的參數(shù),如果在項(xiàng)目中有較高的要求,可以根據(jù)官方提供的API文檔進(jìn)行重構(gòu)。
在項(xiàng)目開發(fā)中,任何一個(gè)功能是無(wú)法做法完成所有的功能,在編碼功能時(shí),只能盡可能的考慮到方法的通用性,在理解了某一個(gè)類和某一個(gè)插件的基本原理和使用方法后,可以根據(jù)對(duì)應(yīng)的API進(jìn)行添加新功能。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Unity 通過(guò)LineRenderer繪制兩點(diǎn)之間的直線操作
這篇文章主要介紹了Unity 通過(guò)LineRenderer繪制兩點(diǎn)之間的直線操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04C#定制Excel界面并實(shí)現(xiàn)與數(shù)據(jù)庫(kù)交互的方法
這篇文章主要介紹了C#定制Excel界面并實(shí)現(xiàn)與數(shù)據(jù)庫(kù)交互的方法的相關(guān)資料,需要的朋友可以參考下2015-11-11C#強(qiáng)制轉(zhuǎn)換和嘗試轉(zhuǎn)換的方法
這篇文章主要為大家詳細(xì)介紹了C#強(qiáng)制轉(zhuǎn)換和嘗試轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09C#調(diào)用FFmpeg操作音視頻的實(shí)現(xiàn)示例
本文主要介紹了C#調(diào)用FFmpeg操作音視頻的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01C#基于正則表達(dá)式抓取a標(biāo)簽鏈接和innerhtml的方法
這篇文章主要介紹了C#基于正則表達(dá)式抓取a標(biāo)簽鏈接和innerhtml的方法,結(jié)合實(shí)例形式分析了C#使用正則表達(dá)式進(jìn)行頁(yè)面元素的匹配與抓取相關(guān)操作技巧,需要的朋友可以參考下2017-06-06在winform下實(shí)現(xiàn)左右布局多窗口界面的方法之續(xù)篇
這篇文章主要介紹了在winform下實(shí)現(xiàn)左右布局多窗口界面的方法之續(xù)篇 的相關(guān)資料,需要的朋友可以參考下2016-02-02