你是否遇到过这样的开发场景:需要在某个应用程序关闭后自动执行清理操作?或者开发自动化测试工具时,需要等待被测应用退出后生成测试报告?又或者在开发插件管理器时,需要在主程序关闭后清理临时文件?
这些看似复杂的需求,其实都指向一个核心问题:如何在C#中准确检测其他应用程序是否已经关闭。本文将为你提供6种实战级解决方案,从基础到高级,让你轻松应对各种监控场景。
在实际开发中,我们经常需要监控其他应用程序的状态,主要痛点包括:
针对这些问题,我们需要根据不同场景选择合适的监控策略。
最直接的方法是使用.NET内置的System.Diagnostics.Process类:
C#using System.Diagnostics;
namespace AppProcessMonitor
{
internal class Program
{
static void Main(string[] args)
{
// 要监控的应用程序名称(不含.exe扩展名)
string processName = "notepad";
Console.WriteLine($"开始监控 {processName} 进程...");
// 首先检查进程是否正在运行
if (!IsProcessRunning(processName))
{
Console.WriteLine($"{processName} 进程未运行!");
return;
}
// 持续监控进程状态直到关闭
while (IsProcessRunning(processName))
{
Console.WriteLine($"{processName} 正在运行中...");
Thread.Sleep(1000); // 每秒检查一次
}
Console.WriteLine($"🎉 {processName} 已关闭!");
// 在这里执行应用关闭后的操作
}
/// <summary>
/// 检查指定名称的进程是否正在运行
/// </summary>
static bool IsProcessRunning(string processName)
{
Process[] processes = Process.GetProcessesByName(processName);
return processes.Length > 0;
}
}
}

适用场景:简单的进程存在性检查,开发调试阶段
优点:代码简单,易于理解
注意事项:频繁轮询可能影响性能
使用Process对象的事件机制,避免轮询带来的性能开销:
C#using System;
using System.Diagnostics;
class EventDrivenMonitor
{
static void Main(string[] args)
{
int processId = GetTargetProcessId("notepad");
if (processId == -1)
{
Console.WriteLine("目标进程未找到!");
return;
}
try
{
Process process = Process.GetProcessById(processId);
// 🔥 关键:启用事件触发
process.EnableRaisingEvents = true;
// 注册进程退出事件
process.Exited += (sender, e) =>
{
Console.WriteLine($"🎯 检测到进程退出! 退出代码: {process.ExitCode}");
// 在这里执行关闭后的业务逻辑
ExecuteCleanupTasks();
};
Console.WriteLine($"正在监控进程ID: {processId}");
process.WaitForExit(); // 阻塞等待进程退出
}
catch (ArgumentException)
{
Console.WriteLine("进程不存在或已关闭");
}
}
static int GetTargetProcessId(string processName)
{
Process[] processes = Process.GetProcessesByName(processName);
return processes.Length > 0 ? processes[0].Id : -1;
}
static void ExecuteCleanupTasks()
{
Console.WriteLine("执行清理任务...");
// 添加你的清理代码
}
}

适用场景:需要精确时间点响应的监控需求
优点:零延迟检测,无性能开销
黄金实践:记得设置EnableRaisingEvents = true
适合需要周期性检查状态并执行其他任务的场景:
C#using System;
using System.Diagnostics;
using System.Timers;
class TimerBasedMonitor
{
private static Timer _monitorTimer;
private static string _targetProcessName;
private static bool _wasRunning = false;
static void Main(string[] args)
{
_targetProcessName = "notepad";
StartMonitoring(TimeSpan.FromSeconds(2));
Console.WriteLine("监控已启动,按Enter键停止...");
Console.ReadLine();
StopMonitoring();
}
static void StartMonitoring(TimeSpan interval)
{
_wasRunning = IsProcessRunning(_targetProcessName);
_monitorTimer = new Timer(interval.TotalMilliseconds);
_monitorTimer.Elapsed += OnTimerElapsed;
_monitorTimer.AutoReset = true;
_monitorTimer.Start();
}
static void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
bool isRunning = IsProcessRunning(_targetProcessName);
// 🎯 状态变化检测:从运行到停止
if (_wasRunning && !isRunning)
{
Console.WriteLine($"🚨 {_targetProcessName} 已关闭!");
OnProcessClosed();
}
// 从停止到运行
else if (!_wasRunning && isRunning)
{
Console.WriteLine($"▶️ {_targetProcessName} 已启动!");
}
_wasRunning = isRunning;
}
static void OnProcessClosed()
{
// 在这里添加进程关闭后的处理逻辑
Console.WriteLine("执行应用关闭后的操作...");
}
static bool IsProcessRunning(string processName)
{
return Process.GetProcessesByName(processName).Length > 0;
}
static void StopMonitoring()
{
_monitorTimer?.Stop();
_monitorTimer?.Dispose();
}
}

适用场景:需要同时监控多个应用或执行周期性任务
性能建议:监控间隔建议设置在500ms-2s之间,平衡及时性和性能
专门针对有界面的应用程序进行监控:
C#using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Timers;
using Timer = System.Timers.Timer;
namespace AppProcessMonitor
{
internal class Program
{
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
static void Main(string[] args)
{
string windowTitle = "notepad";
IntPtr windowHandle = FindWindowByTitle(windowTitle);
if (windowHandle == IntPtr.Zero)
{
Console.WriteLine($"未找到包含 '{windowTitle}' 的窗口");
return;
}
GetWindowThreadProcessId(windowHandle, out uint processId);
Console.WriteLine($"找到窗口,进程ID: {processId}");
// 持续监控窗口是否存在
while (IsWindow(windowHandle))
{
Thread.Sleep(500);
}
Console.WriteLine("🎊 窗口已关闭!");
HandleWindowClosed();
}
static IntPtr FindWindowByTitle(string partialTitle)
{
Process[] processes = Process.GetProcesses();
foreach (Process process in processes)
{
if (!string.IsNullOrEmpty(process.MainWindowTitle) &&
process.MainWindowTitle.Contains(partialTitle))
{
return process.MainWindowHandle;
}
}
return IntPtr.Zero;
}
static void HandleWindowClosed()
{
Console.WriteLine("执行窗口关闭后的处理...");
}
}
}
适用场景:监控特定窗口应用,UI自动化测试
优势:能够监控特定窗口,支持窗口标题匹配
局限性:仅适用于有界面的应用程序
C#// ❌ 错误:忘记启用事件
Process process = Process.GetProcessById(id);
process.Exited += OnProcessExited; // 不会触发!
// ✅ 正确:必须启用事件
process.EnableRaisingEvents = true;
process.Exited += OnProcessExited;
// ❌ 错误:资源泄漏
while (true)
{
Process.GetProcessesByName("app"); // 每次都创建新对象
}
// ✅ 正确:及时释放资源
using (var timer = new Timer())
{
// 监控逻辑
} // 自动释放
本文介绍了6种C#监控应用程序关闭的方法,从简单的Process类轮询到企业级的WMI监控,再到高精度的进程间通信。每种方法都有其适用场景:
选择合适的监控策略,能让你的C#应用更加智能和可靠。记住,没有最好的方法,只有最适合的方案!
💬 技术交流时间:
觉得文章有用的话,别忘了转发给更多C#开发同行! 🚀
#C#开发 #进程监控 #编程技巧 #系统编程
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!