System.Diagnostics.Process 提供系統進程列舉、模組資訊、記憶體使用、視窗標題等豐富屬性。本文示範從列舉所有進程、依名稱篩選、依主視窗標題精確識別並關閉特定實例的完整流程,解決「同名進程多實例」的精確控制問題。
using System.Diagnostics;
Process[] allProcesses = Process.GetProcesses();
foreach (Process p in allProcesses)
{
Console.WriteLine($"PID: {p.Id,6} | Name: {p.ProcessName,-20} | Title: {p.MainWindowTitle}");
}
// 取得所有名為 "notepad" 的進程
Process[] notepads = Process.GetProcessesByName("notepad");
foreach (Process p in notepads)
{
Console.WriteLine($"PID: {p.Id} | Title: '{p.MainWindowTitle}' | Handle: 0x{p.MainWindowHandle:X}");
}
Process.GetProcessesByName 回傳同名進程陣列,若直接迴圈 Kill() 會關閉所有實例。需結合 MainWindowHandle 與 MainWindowTitle 精確定位。
using System;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
public class ProcessManager
{
private ListBox lstProcessNames;
private ListBox lstWindowTitles;
private ArrayList windowHandles = new ArrayList();
public void RefreshProcessList()
{
lstProcessNames.Items.Clear();
Process[] processes = Process.GetProcesses();
foreach (Process p in processes)
{
lstProcessNames.Items.Add(p.ProcessName);
}
}
public void OnProcessSelected(string selectedProcessName)
{
lstWindowTitles.Items.Clear();
windowHandles.Clear();
Process[] processes = Process.GetProcessesByName(selectedProcessName);
foreach (Process p in processes)
{
// 只顯示有主視窗的進程
if (p.MainWindowHandle != IntPtr.Zero)
{
lstWindowTitles.Items.Add(p.MainWindowTitle);
windowHandles.Add(p.MainWindowHandle);
}
}
}
public void CloseSelectedWindow(int selectedIndex)
{
if (selectedIndex < 0 || selectedIndex >= windowHandles.Count) return;
IntPtr targetHandle = (IntPtr)windowHandles[selectedIndex];
string targetTitle = lstWindowTitles.Items[selectedIndex].ToString();
Process[] processes = Process.GetProcessesByName(lstProcessNames.SelectedItem.ToString());
foreach (Process p in processes)
{
if (p.MainWindowHandle == targetHandle)
{
try
{
p.Kill();
lstWindowTitles.Items.RemoveAt(selectedIndex);
windowHandles.RemoveAt(selectedIndex);
MessageBox.Show($"已關閉:{targetTitle}");
}
catch (Exception ex)
{
MessageBox.Show($"關閉失敗:{ex.Message}");
}
break;
}
}
}
}
MainWindowHandle 為 IntPtr.Zero 時無法用視窗標題識別,替代方案:
| 方法 | 適用場景 | 程式碼片段 |
|---|---|---|
| PID 識別 | 已知具體 PID | Process.GetProcessById(pid) |
| 命令列參數 | 啟動參數不同 | WMI: new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process") |
| 模組路徑 | 同名但路徑不同 | p.MainModule.FileName (需權限) |
| 啟動時間 | 不同時段啟動 | p.StartTime |
| 使用者帳戶 | 不同使用者啟動 | WMI: GetOwner() |
using System.Management;
public static void ListProcessDetails()
{
string query = "SELECT ProcessId, Name, CommandLine, ExecutablePath, CreationDate FROM Win32_Process";
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
{
foreach (ManagementObject obj in searcher.Get())
{
Console.WriteLine($"PID: {obj["ProcessId"]} | Name: {obj["Name"]}");
Console.WriteLine($" CmdLine: {obj["CommandLine"]}");
Console.WriteLine($" Path: {obj["ExecutablePath"]}");
Console.WriteLine($" Start: {ManagementDateTimeConverter.ToDateTime(obj["CreationDate"].ToString())}");
// 取得擁有者
string[] args = { "", "" };
obj.InvokeMethod("GetOwner", args);
Console.WriteLine($" Owner: {args[0]}\\{args[1]}");
}
}
}
app.manifest 設定 Kill() 可能被安全軟體攔截,需例外處理CloseMainWindow() 發送關閉訊息
// 1. 優雅關閉:發送 WM_CLOSE 訊息,讓程式自行處理儲存確認
if (p.CloseMainWindow())
{
// 等待結束
p.WaitForExit(5000);
if (!p.HasExited) p.Kill(); // 逾時再強制
}
// 2. 直接強制終止
p.Kill();
public class ProcessManagerForm : Form
{
private ListBox lstProcesses, lstWindows;
private Button btnRefresh, btnClose;
private ArrayList handles = new ArrayList();
public ProcessManagerForm()
{
// UI 初始化...
btnRefresh.Click += (s,e) => LoadProcesses();
lstProcesses.SelectedIndexChanged += (s,e) => LoadWindows();
btnClose.Click += (s,e) => CloseWindow();
}
void LoadProcesses()
{
lstProcesses.Items.Clear();
foreach (Process p in Process.GetProcesses())
lstProcesses.Items.Add(p.ProcessName);
}
void LoadWindows()
{
lstWindows.Items.Clear(); handles.Clear();
if (lstProcesses.SelectedItem == null) return;
foreach (Process p in Process.GetProcessesByName(lstProcesses.SelectedItem.ToString()))
{
if (p.MainWindowHandle != IntPtr.Zero)
{
lstWindows.Items.Add($"[{p.Id}] {p.MainWindowTitle}");
handles.Add(p.MainWindowHandle);
}
}
}
void CloseWindow()
{
if (lstWindows.SelectedIndex < 0) return;
IntPtr h = (IntPtr)handles[lstWindows.SelectedIndex];
foreach (Process p in Process.GetProcessesByName(lstProcesses.SelectedItem.ToString()))
{
if (p.MainWindowHandle == h)
{
p.CloseMainWindow(); // 優雅關閉
if (!p.WaitForExit(3000)) p.Kill();
break;
}
}
LoadWindows();
}
}
C# 進程管理的核心在於 Process.GetProcessesByName 取得同名進程群組,結合 MainWindowHandle 與 MainWindowTitle 實現實例級精確識別。無視窗進程需改用 WMI 查詢命令列、模組路徑、擁有者等屬性區分。實務開發中應優先嘗試 CloseMainWindow() 優雅關閉,失敗再回退 Kill(),並妥善處理權限與安全軟體攔截問題。