This article mainly introduces the suspension and recovery operation methods of processes in C#. It is very good and has reference value. Friends in need can refer to it
1. Origin:
is still the demand caused by modularizationprogramming. Product managers are difficult to serve, and female product managers are even more difficult~:p
This is purely a joke, the technical solution has nothing to do with the product manager, don’t blame Taro!
VCU10 project reconstruction requires each functional module to be implemented in an independent process. For example, if the audio and video conversion module is implemented in an independent process, how to control its pause, continue and other functions?
Threads can Suspend and Resume, but the built-in Process in C# does not have such methods. What should I do?
The mountains and rivers are exhausted and there is no way out, but there is another village with dark flowers and bright flowers. When the love becomes strong, it turns clear and becomes weak. This love can be remembered in memory!
The previous article described the data transfer method between processes. This article also uses examples to demonstrate the control and data interaction methods.
2. Unpublished API functions: NtSuspendProcess, NtResumeProcess
Such functions cannot be found in MSDN.
Thinking about the reason, it is probably because they are between the Windows API and the kernel API, and their power cannot be underestimated. I was afraid that the programmers of 28 Rakes might abuse it and cause trouble, so I hid it secretly.
In fact, there is also NtTerminateProcess, because Process has a Kill method, so it is not needed.
But no matter how secretive something is, as long as it has value, it will be dug out by others. Isn’t good wine afraid of deep alleys?
Okay, based on it, design a process management class to realize the need for inter-process control of modular programming.
3. ProcessMgr
Let’s go straight to the code and encapsulate a process management unit:
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 control
The main process is the host. It calls the child process through the Process class and gets its ID for use. The calling code is:
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); ... }
The control code is:
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); } }
The sub-process simulates its work with a timer and throws a progress message to the main process:
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); }
The amount of code is so small, let’s keep it simple...
5. Rendering:
is an example, and I made two In the figure, one shows the child process and the other shows the child process.
The actual project calls the independent process module, which is called in a hidden way, and the host displays its processing progress, as shown in the picture:
Postscript:
Expanding the idea, some excellent open source tools, such as youtube_dl, ffmpeg, etc., exist as independent processes and can manage communication through CMD.
Based on this process control principle, pretty good GUI tools can be made based on these open source tools. After all, compared to the powerful command line, people still regard simple operations as convenient.
The above is the detailed content of Code example analysis of process suspension and recovery in C# (picture). For more information, please follow other related articles on the PHP Chinese website!