如何等待将要启动的进程?

6
我的应用程序需要等待特定的进程启动。我是这样做的:
while (Process.GetProcessesByName("someProcess").Length == 0)
{
    Thread.Sleep(100);
}

有没有其他更优雅的方式来实现这个功能,类似于 WaitForExit()?谢谢回答。

WaitForInputIdle(http://msdn.microsoft.com/en-us/library/8d7363e2.aspx)函数可让您了解何时消息泵应用程序空闲。这可用于查看进程何时完成加载,但我猜您甚至不知道它是否已开始加载。 - Lars Truijens
2个回答

8
请查看ManagementEventWatcher类。
具体而言,链接底部的代码示例向您展示如何设置ManagementEventWatcher以在创建新进程时通知您。
代码从MSDN代码示例中复制(可能需要进行一些清理):
using System;
using System.Management;

// This example shows synchronous consumption of events. 
// The client is blocked while waiting for events. 

public class EventWatcherPolling 
{
    public static int Main(string[] args) 
    {
        // Create event query to be notified within 1 second of 
        // a change in a service
        WqlEventQuery query = 
            new WqlEventQuery("__InstanceCreationEvent", 
            new TimeSpan(0,0,1), 
            "TargetInstance isa \"Win32_Process\"");

        // Initialize an event watcher and subscribe to events 
        // that match this query
        ManagementEventWatcher watcher =
            new ManagementEventWatcher();
        watcher.Query = query;
        // times out watcher.WaitForNextEvent in 5 seconds
        watcher.Options.Timeout = new TimeSpan(0,0,5);

        // Block until the next event occurs 
        // Note: this can be done in a loop if waiting for 
        //        more than one occurrence
        Console.WriteLine(
            "Open an application (notepad.exe) to trigger an event.");
        ManagementBaseObject e = watcher.WaitForNextEvent();

        //Display information from the event
        Console.WriteLine(
            "Process {0} has been created, path is: {1}", 
            ((ManagementBaseObject)e
            ["TargetInstance"])["Name"],
            ((ManagementBaseObject)e
            ["TargetInstance"])["ExecutablePath"]);

        //Cancel the subscription
        watcher.Stop();
        return 0;
    }
}

编辑

添加了TargetInstance.Name = 'someProcess'过滤器的简化示例。

  var query = new WqlEventQuery(
                "__InstanceCreationEvent", 
                new TimeSpan(0, 0, 1), 
                "TargetInstance isa \"Win32_Process\" and TargetInstance.Name = 'someProcess'"
              );

  using(var watcher = new ManagementEventWatcher(query))
  {
    ManagementBaseObject e = watcher.WaitForNextEvent();

    //someProcess created.

    watcher.Stop();
  }

感谢您的回答,哪种方法更好(对CPU更方便),使用ManagementEventWatcher还是像我代码中那样主动等待?谢谢。 - sanjuro
@sanjuro - WMI是推荐的方法;在C#中轮询进程列表是一项昂贵的操作。我没有明确的统计数据可供审查;但如果您真的担心,您可以随时在本地运行一些比较(话虽如此,我只会在这被视为性能瓶颈时才会担心它)。 - Chris Baxter

2
据我所知,Process类中没有任何东西能让它变得简单。
如果您无法控制子进程中的源代码,则应该选择卡尔加里编码器提供的WMI解决方案。
如果您可以控制子进程中的代码,则有几种额外的方法可以解决这个问题。我已经使用了WCF(使用IPC绑定)、.Net RemotingMutex
这些解决方案的优点是子进程必须选择加入。子进程可以自由等待完成启动初始化程序后再通知父应用程序它已经“准备好了”。
这些链接中都有示例代码,可以帮助您开始解决问题。如果您对某个特定的解决方案感兴趣,并且遇到问题,请告诉我,我会为该特定解决方案发一些样本代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接