在 C# 中终止进程时,我如何确定我正在终止正确的进程?

When killing a process in C#, how can I be sure I'm killing the right one?

总体目标

我正试图终止我当前拥有的某个名称(notepad.exe 下面)的所有进程。一般来说,它是这样的:

问题

到目前为止我有什么

下面的代码基于另一个 SO 答案并使用 WMI 通过特定名称获取所有进程并列出用户。

下一步:下一步是杀死我拥有的进程;但是,我怎么知道我这里的 PID 将与我试图杀死的 PID 相同?

static void Main(string[] args)
    {
        const string PROCESS_NAME = "notepad.exe";
        var queryString = string.Format("Name = '{0}'", PROCESS_NAME);

        var propertiesToSelect = new[] { "Handle", "ProcessId" };
        var processQuery = new SelectQuery("Win32_Process", queryString, propertiesToSelect);

        using (var searcher = new ManagementObjectSearcher(processQuery))
        {
            using (var processes = searcher.Get())
                foreach (var aProcess in processes)
                {
                    var process = (ManagementObject)aProcess;
                    var outParameters = new object[2];
                    var result = (uint)process.InvokeMethod("GetOwner", outParameters);

                    if (result == 0)
                    {
                        var user = (string)outParameters[0];
                        var domain = (string)outParameters[1];
                        var processId = (uint)process["ProcessId"];

                        Console.WriteLine("PID: {0} | User: {1}\{2}", processId, domain, user);
                        // TODO: Use process data...
                    }
                    else
                    {
                        // TODO: Handle GetOwner() failure...
                    }
                }

        }

        Console.ReadLine();
    }

是的,有杀错进程的风险。 PID的重用大概是一个历史事故,多年来引起了很多悲痛。

这样做:

  1. 找到您要杀死的 PID。
  2. 获取这些进程的句柄以稳定 PID。请注意,这可能会获得 错误的 进程的句柄。
  3. 重新找到您要杀死的 PID。
  4. 杀死那些你已经稳定的并且在第二个查找结果集中的进程。

通过插入这个锁定和验证步骤,您可以确定。

从我获取一个 PID 到我杀死它的时间,有多大可能产生了另一个使用该 PID 的应用程序?

如果另一个应用程序是在另一个应用程序处于活动状态时生成的,则不会为其分配相同的 PID。所以这种情况不会发生,因为 Windows' PID 是该特定进程的唯一十进制数字。

如果我抓取一个 ID 为 123 的 PID,它可能已经关闭并且另一个应用程序现在拥有 PID 123 的可能性有多大?

这在技术上是可行的,即可以在您获得对进程的处理时间和您想要终止它之间关闭该进程。但是,这将完全取决于代码中流程处理的生命周期。我想总会有应用程序可能会在您即将挂钩时关闭的边缘情况,但如果您正在谈论 milliseconds/a 几秒钟,我想它会很少而且相距甚远。至于 Windows 之后立即分配相同的 PID,我不确定,但它们看起来很随机,现在在使用后立即再次分配,但它们最终会这样做。

在限制我关闭错误 PID 的可能性的同时合理地实现这一目标的最佳方法是什么?

管理事件观察器 class 似乎允许您监视进程的启动和停止。也许这可以用于在您给定的进程名称关闭时捕获事件,这样您就知道它不再存在了?

Another answer discussing Management Event Watcher

MSDN ManagementEventWatcher class with example usage

考虑相反的方法 - 调整服务帐户的权限,使其不能终止其他用户的进程。

我相信这样的权限非常接近非管理员帐户的默认值(或只是默认值) - 所以除非你 运行 服务作为框 admin/system 你可能没有代码解决方案.

只要进程继续 运行,进程 ID 就保证保持不变。一旦进程退出...就无法保证了。

当新进程启动时,Windows 将随机选择一个进程 ID 并将其分配给新进程。不太可能,但有可能选择的 ID 与最近退出的进程相关联。

你看过System.Diagnostics.Process了吗?

他们有一个 GetProcessesByName 方法,该方法将 return Process 对象列表。

Process [] localByName = Process.GetProcessesByName("notepad");

然后您可以简单地遍历进程并杀死它们。由于 Process 对象具有进程的句柄...尝试终止它会生成一个有用的异常,您可以捕获该异常。

foreach (Process p in localByName)
{
   try
   {
        p.Kill();
   }
   catch (Exception e)
   {
       // process either couldn't be terminated or was no longer running
   }
}