C#中進程的掛起與復原的程式碼實例分析(圖)
這篇文章主要介紹了C#中進程的掛起與恢復操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
1. 源起:
仍然是模組化程式所引發的需求。產品經理難伺候,女產品經理更甚之~:p
純粹是戲謔,技術方案與產品經理無關,芋頭莫怪!
VCU10專案重構,要求各功能模組以獨立進程方式實現,例如:音訊視訊轉換模組,若以獨立進程方式實現,如何控制其暫停、繼續等功能?
執行緒可以Suspend、Resume,c#內建的Process沒有這類方法,咋整?
山窮水盡疑無路,柳暗花明又一村。情到濃時清轉薄,此情可待成追憶!
前篇描述了進程間資料傳遞方法,此篇亦以範例示範其間控制與資料互動方法。
2、未公開的API函數:NtSuspendProcess、NtResumeProcess
這類函數在MSDN中找不到。
思其原因,概因它們介於Windows API和 核心API之間,威力不容小覷。怕二八耙子程式設計師濫用而引發事端,因此密藏。
其實也有NtTerminateProcess,因Process有Kill方法,因此可不用。
但再隱密的東西,只要有價值,都會被人給翻出來,好酒不怕巷子深麼!
好,基於其,設計一個行程管理類,實現模組化程式設計之進程間控制這個需求。
3、ProcessMgr
直上程式碼吧,封裝一個行程管理單元:
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.進程控制
我權且主進程為宿主,它透過Process類別呼叫子進程,得其ID,以此為用。其呼叫代碼為:
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("子进程ID:{0}\r\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 = "恢复"; ProcessMgr.SuspendProcess(this.childProcess.Id); } else { btnWork.Tag = 0; btnWork.Text = "挂起"; ProcessMgr.ResumeProcess(this.childProcess.Id); } }
子程序以一定時器模擬其工作,向主程序拋進度訊息:
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); }
程式碼量就這麼的少,簡單吧…
5、效果圖:
為範例,做了兩個圖,其一為顯示子進程,其二為隱藏子進程。
實際專案呼叫獨立進程模組,是以隱藏方式呼叫的,以宿主展示其處理進度,如此圖:
後記:
擴充思路,一些優秀的開源工具,如youtube_dl、ffmpeg等,都以獨立進程方式存在,且可透過CMD管理通訊。
以此流程控制原理,可以基於這些開源工具,做出相當不錯的GUI工具出來。畢竟相對於強大的命令列,人們還是以簡單操作為方便。
以上是C#中進程的掛起與復原的程式碼實例分析(圖)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

使用 C# 的 Active Directory 指南。在這裡,我們討論 Active Directory 在 C# 中的介紹和工作原理以及語法和範例。

多線程和異步的區別在於,多線程同時執行多個線程,而異步在不阻塞當前線程的情況下執行操作。多線程用於計算密集型任務,而異步用於用戶交互操作。多線程的優勢是提高計算性能,異步的優勢是不阻塞 UI 線程。選擇多線程還是異步取決於任務性質:計算密集型任務使用多線程,與外部資源交互且需要保持 UI 響應的任務使用異步。
