首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 取得系統進程與結束指定進程:Process 類別實戰、權限處理與現代替代方案

     編輯:關於C語言

核心類別:System.Diagnostics.Process

提供**列舉、啟動、監控、終止**作業系統進程的完整功能,支援本機與遠端機器 (需權限)。

列舉所有進程

using System.Diagnostics;

Process[] allProcesses = Process.GetProcesses(); // 本機
// Process.GetProcesses("remoteMachine"); // 遠端 (需 RPC/防火牆/權限)

foreach (Process p in allProcesses)
{
    try
    {
        Console.WriteLine($"PID: {p.Id,6} | Name: {p.ProcessName,-20} | Mem: {p.WorkingSet64/1024/1024,6} MB | Path: {p.MainModule?.FileName ?? "N/A"}");
    }
    catch (System.ComponentModel.Win32Exception)
    {
        Console.WriteLine($"PID: {p.Id,6} | Name: {p.ProcessName,-20} | <存取被拒絕/系統進程>");
    }
}

關鍵屬性

  • `Id` (PID)、`ProcessName` (不含 .exe)、`MainWindowTitle` (主視窗標題)、`MainModule.FileName` (完整路徑)、`WorkingSet64` (記憶體工作集)、`StartTime`、`TotalProcessorTime`。
  • `MainModule` 需**同位元數存取** (x64 進程查 x64,x86 查 x86),否則拋 `Win32Exception`。Any CPU 專案勾選 **Prefer 32-bit** 會導致 x64 系統上以 32 位運行,無法枚舉 64 位進程模組 → **取消勾選 Prefer 32-bit** 或針對 x64 編譯。

依名稱查找並結束進程

public static void KillByName(string processName, bool killAll = false)
{
    // 移除副檔名
    if (processName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
        processName = processName[..^4];

    Process[] processes = Process.GetProcessesByName(processName);
    if (processes.Length == 0)
    {
        Console.WriteLine($"找不到進程: {processName}");
        return;
    }

    foreach (Process p in processes)
    {
        try
        {
            Console.WriteLine($"終止 PID:{p.Id} [{p.ProcessName}]");
            p.Kill(); // 強制終止 (SIGTERM/SIGKILL)
            p.WaitForExit(2000); // 等待結束
            if (!p.HasExited) Console.WriteLine($"  ⚠ PID:{p.Id} 未在 2 秒內結束");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"  ❌ 終止失敗 PID:{p.Id} - {ex.Message}");
        }
        finally
        {
            p.Dispose(); // 釋放非託管資源
        }
    }
}

進階:依完整路徑精確匹配 (避免同名誤殺)

public static Process[] FindByExactPath(string exeFullPath)
{
    string target = Path.GetFullPath(exeFullPath).ToLowerInvariant();
    var list = new List();
    foreach (Process p in Process.GetProcesses())
    {
        try
        {
            string path = p.MainModule?.FileName?.ToLowerInvariant();
            if (path == target) list.Add(p);
            else p.Dispose();
        }
        catch { p.Dispose(); }
    }
    return list.ToArray();
}

啟動新進程 (補充)

var startInfo = new ProcessStartInfo
{
    FileName = "notepad.exe",
    Arguments = "readme.txt",
    WorkingDirectory = @"C:\Temp",
    UseShellExecute = true, // true: 關聯開啟/需 UI; false: 重導向 IO/無殼啟動
    CreateNoWindow = false,
    Verb = "runas" // 要求管理員權限 (UAC 提示)
};
Process proc = Process.Start(startInfo);

常見問題與解決

問題原因與解決
`MainModule` 拋 `Win32Exception` (A 32 bit process cannot access a 64 bit process)**位元數不匹配**。專案屬性 → Build → **取消勾選 "Prefer 32-bit"** (Any CPU 64位運行) 或明確 Target x64。
`Kill()` 拋 `UnauthorizedAccessException`**權限不足**:目標進程以更高權限 (System/Admin) 運行,或受保護進程 (防毒、系統關鍵)。需以管理員身分執行本程式。
`GetProcessesByName` 找不到明明在運行的進程**名稱不含 .exe**。`notepad.exe` → `ProcessName` 為 `"notepad"`。
遠端 `GetProcesses("server")` 失敗需**開啟 RPC (TCP 135)、WMI (DCOM)、防火牆例外**、同網域/工作組且具備權限帳號。現代建議用 **WinRM / PowerShell Remoting / SSH** 替代。
大量 `Process` 物件未 `Dispose()` 導致句柄洩漏**務必 `using` 或 `finally { p.Dispose(); }`**。`Process` 實作 `IDisposable`。

現代替代方案:.NET 6+ `Process.GetProcesses()` 效能優化

  • .NET 6+ 內部改用 **`/proc` (Linux) / `sysctl` (macOS) / `NtQuerySystemInformation` (Windows)** 直接讀取,比舊版 `WMI/PDH` **快 10-100 倍**,記憶體佔用大幅降低。
  • 跨平台統一 API:`Process.GetProcesses()` 在 Windows/Linux/macOS 行為一致。

總結

`System.Diagnostics.Process` 是 C# 管理進程的標準工具。**核心操作**:`GetProcesses()` 列舉、`GetProcessesByName()` 依名查找、`Kill()` 強制結束、`Start()` 啟動新進程。**必守鐵律**:**位元數匹配 (關閉 Prefer 32-bit)、權限足夠 (管理員)、資源釋放**。現代 .NET 6+ 已大幅優化跨平台效能,可放心用於高頻監控場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved