C#中進(jìn)程的掛起與恢復(fù)
1. 源起:
仍然是模塊化編程所引發(fā)的需求。產(chǎn)品經(jīng)理難伺候,女產(chǎn)品經(jīng)理更甚之~:p
純屬戲謔,技術(shù)方案與產(chǎn)品經(jīng)理無(wú)關(guān),芋頭莫怪!
VCU10項(xiàng)目重構(gòu),要求各功能模塊以獨(dú)立進(jìn)程方式實(shí)現(xiàn),比如:音視頻轉(zhuǎn)換模塊,若以獨(dú)立進(jìn)程方式實(shí)現(xiàn),如何控制其暫停、繼續(xù)等功能呢?
線程可以Suspend、Resume,c#內(nèi)置的Process沒(méi)有此類方法,咋整?
山窮水盡疑無(wú)路,柳暗花明又一村。情到濃時(shí)清轉(zhuǎn)薄,此情可待成追憶!
前篇描述了進(jìn)程間數(shù)據(jù)傳遞方法,此篇亦以示例演示其間控制與數(shù)據(jù)交互方法。
2、未公開(kāi)的API函數(shù):NtSuspendProcess、NtResumeProcess
此類函數(shù)在MSDN中找不到。
思其原因,概因它們介于Windows API和 內(nèi)核API之間,威力不容小覷。怕二八耙子程序員濫用而引發(fā)事端,因此密藏。
其實(shí)還有個(gè)NtTerminateProcess,因Process有Kill方法,因此可不用。
但再隱秘的東西,只要有價(jià)值,都會(huì)被人給翻出來(lái),好酒不怕巷子深么!
好,基于其,設(shè)計(jì)一個(gè)進(jìn)程管理類,實(shí)現(xiàn)模塊化編程之進(jìn)程間控制這個(gè)需求。
3、ProcessMgr
直上代碼吧,封裝一個(gè)進(jìn)程管理單元:
public static class ProcessMgr { /// <summary> /// The process-specific access rights. /// </summary> [Flags] public enum ProcessAccess : uint { /// <summary> /// Required to terminate a process using TerminateProcess. /// </summary> Terminate = 0x1, /// <summary> /// Required to create a thread. /// </summary> CreateThread = 0x2, /// <summary> /// Undocumented. /// </summary> SetSessionId = 0x4, /// <summary> /// Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory). /// </summary> VmOperation = 0x8, /// <summary> /// Required to read memory in a process using ReadProcessMemory. /// </summary> VmRead = 0x10, /// <summary> /// Required to write to memory in a process using WriteProcessMemory. /// </summary> VmWrite = 0x20, /// <summary> /// Required to duplicate a handle using DuplicateHandle. /// </summary> DupHandle = 0x40, /// <summary> /// Required to create a process. /// </summary> CreateProcess = 0x80, /// <summary> /// Required to set memory limits using SetProcessWorkingSetSize. /// </summary> SetQuota = 0x100, /// <summary> /// Required to set certain information about a process, such as its priority class (see SetPriorityClass). /// </summary> SetInformation = 0x200, /// <summary> /// Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob). /// </summary> QueryInformation = 0x400, /// <summary> /// Undocumented. /// </summary> SetPort = 0x800, /// <summary> /// Required to suspend or resume a process. /// </summary> SuspendResume = 0x800, /// <summary> /// Required to retrieve certain information about a process (see QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. /// </summary> QueryLimitedInformation = 0x1000, /// <summary> /// Required to wait for the process to terminate using the wait functions. /// </summary> Synchronize = 0x100000 } [DllImport("ntdll.dll")] private static extern uint NtResumeProcess([In] IntPtr processHandle); [DllImport("ntdll.dll")] private static extern uint NtSuspendProcess([In] IntPtr processHandle); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr OpenProcess( ProcessAccess desiredAccess, bool inheritHandle, int processId); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle([In] IntPtr handle); public static void SuspendProcess(int processId) { IntPtr hProc = IntPtr.Zero; try { // Gets the handle to the Process hProc = OpenProcess(ProcessAccess.SuspendResume, false, processId); if (hProc != IntPtr.Zero) NtSuspendProcess(hProc); } finally { // Don't forget to close handle you created. if (hProc != IntPtr.Zero) CloseHandle(hProc); } } public static void ResumeProcess(int processId) { IntPtr hProc = IntPtr.Zero; try { // Gets the handle to the Process hProc = OpenProcess(ProcessAccess.SuspendResume, false, processId); if (hProc != IntPtr.Zero) NtResumeProcess(hProc); } finally { // Don't forget to close handle you created. if (hProc != IntPtr.Zero) CloseHandle(hProc); } } }
4、進(jìn)程控制
我權(quán)且主進(jìn)程為宿主,它通過(guò)Process類調(diào)用子進(jìn)程,得其ID,以此為用。其調(diào)用代碼為:
private void RunTestProcess(bool hidden = false) { string appPath = Path.GetDirectoryName(Application.ExecutablePath); string testAppPath = Path.Combine(appPath, "TestApp.exe"); var pi = new ProcessStartInfo(); pi.FileName = testAppPath; pi.Arguments = this.Handle.ToString(); pi.WindowStyle = hidden ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal; this.childProcess = Process.Start(pi); txtInfo.Text = string.Format("子進(jìn)程ID:{0}\r\n子進(jìn)程名:{1}", childProcess.Id, childProcess.ProcessName); ... }
控制代碼為:
private void btnWork_Click(object sender, EventArgs e) { if (this.childProcess == null || this.childProcess.HasExited) return; if ((int)btnWork.Tag == 0) { btnWork.Tag = 1; btnWork.Text = "恢復(fù)"; ProcessMgr.SuspendProcess(this.childProcess.Id); } else { btnWork.Tag = 0; btnWork.Text = "掛起"; ProcessMgr.ResumeProcess(this.childProcess.Id); } }
子進(jìn)程以一定時(shí)器模擬其工作,向主進(jìn)程拋進(jìn)度消息:
private void timer_Tick(object sender, EventArgs e) { if (progressBar.Value < progressBar.Maximum) progressBar.Value += 1; else progressBar.Value = 0; if (this.hostHandle != IntPtr.Zero) SendMessage(this.hostHandle, WM_PROGRESS, 0, progressBar.Value); }
代碼量就這么的少,簡(jiǎn)單吧……
5、效果圖:
為示例,做了兩個(gè)圖,其一為顯示子進(jìn)程,其二為隱藏子進(jìn)程。
實(shí)際項(xiàng)目調(diào)用獨(dú)立進(jìn)程模塊,是以隱藏方式調(diào)用的,以宿主展示其處理進(jìn)度,如此圖:
后記:
擴(kuò)展思路,一些優(yōu)秀的開(kāi)源工具,如youtube_dl、ffmpeg等,都以獨(dú)立進(jìn)程方式存在,且可通過(guò)CMD管理通信。
以此進(jìn)程控制原理,可以基于這些開(kāi)源工具,做出相當(dāng)不錯(cuò)的GUI工具出來(lái)。畢竟相對(duì)于強(qiáng)大的命令行,人們還是以簡(jiǎn)單操作為方便。
上一篇:一個(gè)可攜帶附加消息的增強(qiáng)消息框MessageBoxEx
欄 目:C#教程
下一篇:c# 將Datatable數(shù)據(jù)導(dǎo)出到Excel表格中
本文標(biāo)題:C#中進(jìn)程的掛起與恢復(fù)
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/5805.html
您可能感興趣的文章
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并打開(kāi)的方法
- 01-10關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#停止線程的方法
- 01-10WinForm實(shí)現(xiàn)仿視頻 器左下角滾動(dòng)新聞效果的方法
- 01-10C#通過(guò)重寫(xiě)Panel改變邊框顏色與寬度的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已安裝軟件變化的方法
- 01-10C#實(shí)現(xiàn)多線程下載文件的方法


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻 器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過(guò)重寫(xiě)Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載