Dieser Artikel stellt hauptsächlich die Methode zum Anhalten und Fortsetzen von Prozessen in C# vor. Er ist sehr gut und hat Referenzwert.
1. Ursprung:
ist immer noch die Nachfrage, die durch die ModularisierungProgrammierung entsteht. Produktmanager sind schwer zu bedienen, und weibliche Produktmanager sind noch schwieriger ~:p
Das ist nur ein Scherz, die technische Lösung hat nichts mit dem Produktmanager zu tun, geben Sie Taro nicht die Schuld!
Bei der VCU10-Projektrekonstruktion muss jedes Funktionsmodul in einem unabhängigen Prozess implementiert werden. Wenn beispielsweise das Audio- und Videokonvertierungsmodul in einem unabhängigen Prozess implementiert wird, wie können dann dessen Pause, Fortfahren und andere Funktionen gesteuert werden?
Threads können angehalten und fortgesetzt werden, aber der integrierte Prozess in c# verfügt nicht über solche Methoden. Was soll ich tun?
Die Berge und Flüsse sind erschöpft und es gibt keinen Ausweg, aber es gibt ein anderes Dorf mit dunklen Weiden und leuchtenden Blumen. Wenn die Liebe stark wird, wird sie klar und wird schwach. Diese Liebe kann in Erinnerung bleiben!
Im vorherigen Artikel wurde die prozessübergreifende Datenübertragungsmethode beschrieben. In diesem Artikel werden auch Beispiele verwendet, um die Steuerungs- und Dateninteraktionsmethoden zu demonstrieren.
2. Unveröffentlichte API-Funktionen: NtSuspendProcess, NtResumeProcess
Solche Funktionen können in MSDN nicht gefunden werden.
Der Grund dafür ist, dass sie zwischen der Windows-API und der Kernel-API liegen und ihre Leistungsfähigkeit nicht zu unterschätzen ist. Ich hatte Angst, dass die Programmierer von 28 Rakes es missbrauchen und Ärger verursachen könnten, also habe ich es heimlich versteckt.
Tatsächlich gibt es auch NtTerminateProcess. Da Process über eine Kill-Methode verfügt, wird diese nicht benötigt.
Aber egal wie geheimnisvoll etwas ist, solange es einen Wert hat, wird es von anderen ausgegraben! Guter Wein hat keine Angst vor tiefen Gassen!
Okay, entwerfen Sie darauf basierend eine Prozessmanagementklasse, um die Notwendigkeit einer prozessübergreifenden Steuerung in der modularen Programmierung zu erkennen.
3. ProcessMgr
Gehen wir direkt zum Code und kapseln eine Prozessmanagementeinheit:
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. Prozesssteuerung
Wir haben den Hauptprozess als Host. Er ruft den untergeordneten Prozess über die Process-Klasse auf, um seine ID zu erhalten und ihn für diesen Zweck zu verwenden. Der Aufrufcode lautet:
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); ... }
Der Steuercode lautet:
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); } }
Der Unterprozess simuliert seine Arbeit mit einem Timer und sendet Fortschrittsmeldungen an den Hauptprozess:
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); }
Die Menge an Code ist so klein, einfach...
5. Rendering:
ist Als Beispiel werden zwei Diagramme erstellt, eines zeigt den Unterprozess und das andere zeigt den Unterprozess.
Das eigentliche Projekt ruft das unabhängige Prozessmodul auf, das auf versteckte Weise aufgerufen wird, und der Host zeigt seinen Verarbeitungsfortschritt an, wie im Bild gezeigt:
Postscript:
Um die Idee zu erweitern, existieren einige hervorragende Open-Source-Tools wie youtube_dl, ffmpeg usw. als unabhängige Prozesse und können Verwalten Sie die Kommunikation über CMD.
Mit diesem Prozesssteuerungsprinzip können Sie auf Basis dieser Open-Source-Tools ziemlich gute GUI-Tools erstellen. Denn im Vergleich zur leistungsstarken Befehlszeile empfinden die Menschen einfache Vorgänge immer noch als bequem.
Das obige ist der detaillierte Inhalt vonCodebeispielanalyse der Prozessunterbrechung und -wiederherstellung in C# (Bild). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!