直接调用 Process.GetProcesses() 可获取当前会话及全局可见服务进程的快照数组,但受权限限制(需管理员权限才能访问系统/其他用户进程),且返回值为静态快照、非实时流;常见异常如“拒绝访问”源于 Windows 权限机制,并非代码错误。

怎么用 Process.GetProcesses() 拿到所有进程
直接调用 Process.GetProcesses() 就能拿到当前机器上所有可访问的进程快照,返回的是 Process[] 数组。它不区分用户权限,但受制于当前进程的权限级别——比如以普通用户运行,就看不到系统级进程(如 svchost.exe 的某些实例)或其它用户会话里的进程。
常见错误是没加异常处理,一遇到无权限进程就抛 System.ComponentModel.Win32Exception: 拒绝访问。这不是代码写错了,是 Windows 权限机制在起作用。
- 需要查看完整列表?得用管理员权限启动你的程序,否则必然漏掉一部分
- 想跨用户会话(比如远程桌面多个登录)?
GetProcesses()本身做不到,它只返回当前会话 + 全局可见服务进程,且依赖SeDebugPrivilege权限 - 返回结果是快照,不是实时流;要“刷新”,得重新调用,不能靠监听
为什么 Process.ProcessName 和任务管理器里看到的名字不一致
任务管理器显示的“名称”其实是可执行文件名(不含扩展名),而 Process.ProcessName 返回的也是这个——但它不包含路径、不带版本信息、也不反映窗口标题。所以你会看到:chrome.exe 对应一堆 chrome,Code.exe 全部叫 Code,根本分不清哪个是主窗口、哪个是渲染进程。
真正和任务管理器对齐的方式,是结合 Process.MainWindowTitle 或查 Process.Modules(需管理员权限),但后者开销大、易失败。
-
Process.ProcessName是最轻量的标识,适合按类型统计(比如杀掉所有python进程) - 想区分同名进程?得看
Process.Id、Process.SessionId、或者尝试读Process.MainWindowHandle != IntPtr.Zero判断是否有 GUI - 注意:.NET 6+ 中
Process.StartTime在某些低权限下可能为DateTime.MinValue,别拿它做排序依据
如何安全地避免“拒绝访问”异常并过滤出有效进程
硬 try-catch 每个 Process 属性是最常见的做法,但效率低、掩盖问题。更稳妥的是先获取进程 ID 列表,再逐个尝试打开——或者直接用 Process.GetProcesses() 后立即过滤掉 HasExited == true 的项(虽然概率小,但多线程下真会发生)。
下面这段逻辑能绕过大部分权限问题,又不崩:
var processes = Process.GetProcesses();
var validProcesses = new List<Process>();
foreach (var p in processes)
{
try
{
// 只访问最基础字段,避免触发权限检查
if (!p.HasExited && !string.IsNullOrEmpty(p.ProcessName))
{
validProcesses.Add(p);
}
}
catch (InvalidOperationException) { /* 已退出 */ }
catch (Win32Exception) { /* 拒绝访问,跳过 */ }
}- 不要在循环里调
p.MainWindowTitle或p.Threads,这些极易触发异常 - 如果只要进程名和 ID,用
Process.GetProcesses().Select(p => new { p.Id, p.ProcessName })是安全的 - 在 Windows Server 或多会话环境中,
SessionId == 0通常表示服务会话,普通用户进程 SessionId > 0
任务管理器“详细信息”页的内存/CPU 数据怎么对应到 C#
任务管理器显示的“内存(使用量)”对应 Process.WorkingSet64,不是 PrivateMemorySize64;CPU 占用率它用的是采样差值,C# 里没有现成等价属性,必须自己算 Process.TotalProcessorTime 在两次采样间的增量除以经过时间。
也就是说:你不能只读一次 TotalProcessorTime 就说“CPU 占了 30%”,那只是自进程启动以来的累计占比。
-
WorkingSet64是进程当前占用的物理内存(字节),和任务管理器“内存”列基本一致 - 想模拟任务管理器的 CPU%,至少要间隔 500ms 以上采两次
TotalProcessorTime,再除以(结束时间 - 开始时间).TotalMilliseconds * Environment.ProcessorCount - 注意:.NET Core/.NET 5+ 中
Process.PeakVirtualMemory64在某些容器环境下可能始终为 0,别依赖它做判断
真实环境里,进程列表本身不难拿,难的是怎么在不崩溃、不漏数据、不误导用户的前提下,把“看起来像任务管理器”的信息稳定呈现出来——尤其是权限边界、采样时机、字段语义差异这三块,最容易被当成理所当然而踩坑。










