C#中Process类详解

Process 类位于System.Diagnostics 命名空间下,他提供对本地和远程进程的访问,允许启动 停止 监控与系统进行交互。 无论是启动一个外部程序(如记事本,命令行工具),还是获取当前正在运行的进程列表,Process都是核心工具。

1. 核心概念

  • 进程(Process):正在运行的程序实例,拥有独立的内存空间、资源句柄和线程。

  • Process 类 :封装了对进程的操作,可以启动新进程附加到现有进程查询进程信息等待进程结束读写进程的标准输入/输出等。

  • 命名空间using System.Diagnostics;

2. 常用启动方式

2.1 简单启动(使用默认配置)

csharp

复制代码
 Process.Start("notepad.exe");
 Process.Start("https://www.microsoft.com"); // 打开网址
复制代码
 ProcessStartInfo startInfo = new ProcessStartInfo
 {
     FileName = "ping",                // 可执行文件或命令
     Arguments = "8.8.8.8 -t",         // 参数
     UseShellExecute = false,         // 是否使用操作系统 shell 启动(false 可重定向 IO)
     RedirectStandardOutput = true,   // 重定向标准输出流
     CreateNoWindow = true           // 不显示窗口
 };
 ​
 Process process = new Process { StartInfo = startInfo };
 process.Start();
 string output = process.StandardOutput.ReadToEnd(); // 读取全部输出
 process.WaitForExit();

3. 常用方法详解

方法名 说明
Start() 启动进程,根据 StartInfo 配置启动新进程。静态版本 Process.Start(info) 直接启动并返回 Process 实例。
Kill() 强制终止进程。立即停止,不提供保存数据的机会。
CloseMainWindow() 友好地关闭进程的主窗口(向主窗口发送关闭消息),与用户点击关闭按钮类似。适用于 GUI 程序。
WaitForExit() 同步等待进程退出。可以指定超时时间(毫秒),返回 bool 表示是否在超时前退出。
WaitForInputIdle() 等待进程进入空闲状态,常用于图形界面进程,确保窗口已完成初始化。
Refresh() 刷新进程属性信息(如内存使用、CPU 时间等),使当前实例从操作系统获取最新数据。
GetProcesses() 静态方法,获取本地计算机上所有正在运行的进程数组。
GetProcessesByName(string) 静态方法,根据进程名称获取所有匹配的进程实例(如 "notepad")。
GetProcessById(int) 静态方法,通过进程 ID 获取指定进程。若不存在则抛出异常。
Start(string, string) 静态重载,快速启动程序并传递参数。

4. 常用属性

属性名 说明
Id 当前进程的唯一标识符(PID)。
ProcessName 进程的名称(不含路径,例如 "notepad")。
MainWindowTitle 进程主窗口的标题。
MainModule 进程的主模块信息(包含文件名等)。
HasExited 指示关联的进程是否已终止。
ExitCode 进程退出时代码(需在 HasExited 为 true 时读取)。
StartTime 进程启动的时间。
TotalProcessorTime 进程使用的总处理器时间。
WorkingSet64 进程的物理内存使用量(字节)。
PriorityClass 进程的优先级类(可读写)。
StandardInput / StandardOutput / StandardError 用于重定向输入输出流(需先设置重定向)。

5. 事件处理

Process 类支持两个重要事件:

5.1 Exited 事件

在进程退出时触发。使用前必须将 EnableRaisingEvents 属性设为 true

csharp

复制代码
 process.EnableRaisingEvents = true;
 process.Exited += (sender, e) =>
 {
     Console.WriteLine("进程已退出,退出代码:" + process.ExitCode);
 };
 process.Start();

5.2 OutputDataReceived / ErrorDataReceived 事件

当进程通过标准输出/错误流输出行时触发。需要先设置重定向,并调用 BeginOutputReadLine() 开始异步读取。

csharp

复制代码
 startInfo.RedirectStandardOutput = true;
 startInfo.RedirectStandardError = true;
 process = new Process { StartInfo = startInfo };
 ​
 process.OutputDataReceived += (sender, e) =>
 {
     if (e.Data != null) Console.WriteLine("[输出] " + e.Data);
 };
 process.ErrorDataReceived += (sender, e) =>
 {
     if (e.Data != null) Console.WriteLine("[错误] " + e.Data);
 };
 ​
 process.Start();
 process.BeginOutputReadLine();
 process.BeginErrorReadLine();
 process.WaitForExit();

6. 完整示例:启动并实时读取输出

复制代码
 using System;
 using System.Diagnostics;
 ​
 class Program
 {
     static void Main()
     {
         Process process = new Process();
         ProcessStartInfo startInfo = new ProcessStartInfo
         {
             FileName = "cmd.exe",
             Arguments = "/c dir C:\\",
             UseShellExecute = false,
             RedirectStandardOutput = true,
             RedirectStandardError = true,
             CreateNoWindow = true
         };
         process.StartInfo = startInfo;
 ​
         process.OutputDataReceived += (sender, e) => Console.WriteLine(e.Data);
         process.ErrorDataReceived += (sender, e) => Console.WriteLine("ERR: " + e.Data);
 ​
         process.Start();
         process.BeginOutputReadLine();
         process.BeginErrorReadLine();
         process.WaitForExit();
 ​
         Console.WriteLine("退出码:" + process.ExitCode);
     }
 }

7. 获取系统中运行的进程

复制代码
 // 获取所有进程
 Process[] allProcesses = Process.GetProcesses();
 foreach (Process proc in allProcesses)
 {
     Console.WriteLine($"名称: {proc.ProcessName}, ID: {proc.Id}, 内存: {proc.WorkingSet64 / 1024} KB");
 }
 ​
 // 获取特定名称的进程
 Process[] notepads = Process.GetProcessesByName("notepad");
 if (notepads.Length > 0)
 {
     notepads[0].Kill(); // 强制关闭第一个记事本进程
 }

8. 注意事项

  1. 资源释放Process 实现了 IDisposable,使用完后应调用 Dispose()(或使用 using 语句)释放系统资源。

    csharp

    复制代码
     using (Process p = Process.Start("notepad.exe"))
     {
         // ...
     }
  2. 权限问题:某些操作(如获取已结束进程的退出码、修改远程进程、调试特权进程)可能需要管理员权限。

  3. 异步读取 :如果同时使用 ReadToEnd() 和事件方式,可能造成死锁。建议只采用其中一种。

  4. Shell 使用 :当 UseShellExecute = true 时(默认),可以启动文档、网址等关联程序,但不能重定向 IO。若要重定向,必须设为 false

  5. 64/32位 :从 32 位程序启动 64 位系统目录下的程序可能受文件系统重定向影响,可通过 ProcessStartInfoFileName 指定完整路径,或使用 SysNative 替代 System32 来访问原生 64 位目录。

9. 典型应用场景

  • 调用外部工具:如压缩工具、转换工具、命令行编译器。

  • 自动化操作:控制浏览器打开网页,模拟用户操作(需配合窗口消息或 UI 自动化)。

  • 进程监控:监听程序是否崩溃,自动重启。

  • 系统信息收集:获取当前运行的进程清单、CPU/内存占用。

  • 管道通信:通过标准输入输出流与子进程交互(如执行命令行命令)。

10. 总结

Process 类是 C# 中与操作系统进程交互的万能钥匙。理解它的启动方式、重定向、事件和常用查询方法,能让你轻松实现许多系统级编程任务。通过合理运用 ProcessStartInfo,你可以精细控制外部进程的行为,并安全地与它们交换数据。

掌握 Process,就掌握了 .NET 进程管理的核心。

在C#中,静态Static成员不能直接访问非静态(实例)成员。

静态Static=图纸上的说明书

1. 静态(Static) = 图纸上的说明书

  • 特性:它是全局唯一的,不需要造出机器,图纸上就写着"激光功率上限是 3000W"。

  • 权限:它只能谈论图纸上有的东西,它不知道这台图纸以后会造出 10 台还是 100 台机器。

2. 实例(Instance) = 编号为 001 的激光机

  • 特性 :只有当你按下生产线启动键(new Form1()),这台具体的机器(对象)才存在。

  • 控件(txtBox) :它是这台机器上的一个零件(触摸屏)

静态与实例的关系表

成员类型 所属对象 什么时候存在 能否访问静态成员 能否访问实例成员
静态 (Static) 类(图纸) 程序启动即存在 不能(因为不知道指向哪个实例)
实例 (Instance) 对象(机器) new 出来之后才存在
  • 静态(static)与实例(instance)的隔离:静态方法属于"类"本身,它在程序一运行就存在了。。而实例化成员只有当窗体被创建之后才会存在。

  • 控件是实例成员 :你只有当你运行程序、窗口弹出来的那一刻,这个 控件才真正被"造"出来(实例化)。

  • 违逻辑访问 :静态方法 运行在"上帝视角",它不知道现在屏幕上有哪个具体的 Form 窗口,所以它无法访问属于某个特定窗口的 控件。

相关推荐
柒儿吖2 小时前
三方库 Boost.Regex 在 OpenHarmony 的 lycium完整实践
c++·c#·openharmony
柒儿吖2 小时前
三方库 Emoji Segmenter 在 OpenHarmony 的 lycium 适配与测试
c++·c#·openharmony
hoiii1872 小时前
基于C#实现的高性能实时MP4录屏方案
开发语言·c#
yongui478343 小时前
基于C#实现Modbus RTU通信
开发语言·c#
编码者卢布3 小时前
【Azure Event Hub】在VMSS中使用WAD(Window Azure Diagnostic)插件发送日志到Event Hub中报错分析
microsoft·azure
wula19943 小时前
C# Revit二次开发 地层工程量统计
开发语言·c#
C#程序员一枚3 小时前
大字段查询性能优化终极方案
sql·c#
宇擎智脑科技3 小时前
CopilotKit for LangGraph 深度解析:构建 Agent 原生应用的前端交互框架
前端·人工智能·交互
deephub12 小时前
Agent Lightning:微软开源的框架无关 Agent 训练方案,LangChain/AutoGen 都能用
人工智能·microsoft·langchain·大语言模型·agent·强化学习