【问题标题】:C# - Making a Process.Start wait until the process has start-upC# - 使 Process.Start 等到进程启动
【发布时间】:2011-09-17 09:59:21
【问题描述】:

在继续使用方法之前,我需要确保进程正在运行。

声明是:

Process.Start("popup.exe");

您可以执行 WAIT 命令或对此值设置延迟吗?

【问题讨论】:

  • “确保”是什么意思?在 popup.exe 中必须运行特定的东西,对吗?如果是这样,等待它运行是不够的。
  • 你也可以控制popup.exe吗?这意味着您可以向它添加代码以指示它正在运行的产卵过程吗?

标签: c# .net windows process


【解决方案1】:

你的意思是等到它完成?然后使用Process.WaitForExit:

var process = new Process {
    StartInfo = new ProcessStartInfo {
        FileName = "popup.exe"
    }
};
process.Start();
process.WaitForExit();

或者,如果它是具有 UI 的应用程序,您正在等待进入消息循环,您可以说:

process.Start();
process.WaitForInputIdle();

最后,如果这些都不适用,只需Thread.Sleep 一段合理的时间:

process.Start();
Thread.Sleep(1000); // sleep for one second

【讨论】:

  • 在你的第一个sn-p中,你必须在process.WaitForExit()之前手动调用process.Start();否则会抛出异常。
  • 只要确保你了解 WaitForInputIdle 的实际作用 blogs.msdn.com/b/oldnewthing/archive/2010/03/25/9984720.aspx
  • @ta.speot.is 换句话说... 正是 OP想要什么?
  • @Basic 这是一个参考网站,这个答案可能会被非OP的人阅读。
  • @Eagle-Eye 我不确定我是否理解你的意思? ta.speoit.is(无论是 Q 还是 A 的 OP)暗示该功能没有像宣传的那样工作。我检查了文档,它似乎完全符合 OP 的要求。这会以何种方式降低网站对未来访问者的用处?
【解决方案2】:

我也需要这个,我检查了进程的窗口标题。如果它是您所期望的,您可以确定应用程序正在运行。我正在检查的应用程序需要一些时间才能启动,这种方法对我来说效果很好。

var process = Process.Start("popup.exe");
while(process.MainWindowTitle != "Title")
{
    Thread.Sleep(10);
}

【讨论】:

  • 您可能需要像@AlirezaNaghizadeh 提到的那样在循环中执行proc.Refresh();
【解决方案3】:

'ChrisG'的答案是正确的,但是我们需要每次刷新MainWindowTitle,最好检查一下是否为空...。像这样:

var proc = Process.Start("popup.exe");
while (string.IsNullOrEmpty(proc.MainWindowTitle))
{
    System.Threading.Thread.Sleep(100);
    proc.Refresh();
}

【讨论】:

  • 我们可以假设一个命令行应用程序一旦获得了一个标题它就被启动了吗?
  • 我添加了一个额外的 check in while 语句:!proc.HasExited
【解决方案4】:

首先:我知道这已经很老了,但仍然没有公认的答案,所以也许我的方法会帮助其他人。 :)

我为解决这个问题所做的是:

process.Start();

while (true)
{
    try
    {
        var time = process.StartTime;
        break;
    }
    catch (Exception) {}
}

只要进程没有启动,关联var time = process.StartTime 就会抛出异常。因此,一旦它通过,就可以安全地假设进程正在运行并进一步使用它。我正在使用它来等待 java 进程启动,因为它需要一些时间。这样它应该独立于应用程序正在运行的机器而不是使用Thread.Sleep()

我知道这不是很干净的解决方案,但我能想到的唯一一个应该与性能无关的解决方案。

【讨论】:

  • 虽然这很老套,但它似乎是获取所需信息的最直接方式。
  • 之后调用process.BeginOutputReadLine()Process.BeginErrorReadLine() 会引发异常,明确指出进程尚未完全初始化。
  • 这可能取决于您开始的过程。我的 Java 进程没问题,你的可能需要更多时间来做它需要的事情。但是您仍然可以使用相同的方法,而不是关联调用我猜对您至关重要的任何函数。仍然,像地狱一样的hacky,但应该可以工作。
【解决方案5】:

就像其他人已经说过的那样,您要问什么并不是很明显。我将假设您要启动一个流程,然后在流程“准备就绪”时执行另一个操作。

当然,“准备就绪”是一个棘手的问题。根据您的需求,您可能会发现只需等待就足够了。但是,如果您需要更健壮的解决方案,可以考虑使用名为 Mutex 来控制两个进程之间的控制流。

例如,在您的主进程中,您可能会创建一个命名互斥体并启动一个等待的线程或任务。然后,您可以开始第二个过程。当该进程决定“准备就绪”时,它可以打开命名互斥体(当然,您必须使用相同的名称)并向第一个进程发出信号。

【讨论】:

  • 这正是我在搜索时期望找到的。谢谢。
【解决方案6】:

我同意汤姆的观点。此外,要在执行 Thread.Sleep 时检查进程,请检查正在运行的进程。比如:

bool found = 0;
while (!found)
{
    foreach (Process clsProcess in Process.GetProcesses())
        if (clsProcess.Name == Name)
            found = true;

    Thread.CurrentThread.Sleep(1000);
}

【讨论】:

  • while (!Process.GetProcesses().Any(p=>p.Name == myName)) { Thread.Sleep(100); }
  • 为什么不GetProcessesByName()while(Process.GetProcessesByName(myName).Length == 0) { Thread.Sleep(100); } 虽然它可能在大部分时间都有效,但正确的方法是等到 n 英里秒,如果找不到进程,则退出循环。
【解决方案7】:

您确定Start 方法在子进程启动之前返回吗?我一直觉得Start是同步启动子进程的。

如果您想等到您的子进程完成某种初始化,那么您需要进程间通信 - 请参阅 Interprocess communication for Windows in C# (.NET 2.0)

【讨论】:

    【解决方案8】:

    我使用了EventWaitHandle 类。在父进程上,创建一个名为 EventWaitHandle 的事件初始状态设置为非信号。父进程阻塞,直到子进程调用Set方法,将事件状态变为signaled,如下图。

    父进程:

    using System;
    using System.Threading;
    using System.Diagnostics;
    
    namespace MyParentProcess
    {
        class Program
        {
            static void Main(string[] args)
            {
                EventWaitHandle ewh = null;
                try
                {
                    ewh = new EventWaitHandle(false, EventResetMode.AutoReset, "CHILD_PROCESS_READY");
    
                    Process process = Process.Start("MyChildProcess.exe", Process.GetCurrentProcess().Id.ToString());
                    if (process != null)
                    {
                        if (ewh.WaitOne(10000))
                        {
                            // Child process is ready.
                        }
                    }
                }
                catch(Exception exception)
                { }
                finally
                {
                    if (ewh != null)
                        ewh.Close();
                }
            }
        }
    }
    

    子进程:

    using System;
    using System.Threading;
    using System.Diagnostics;
    
    namespace MyChildProcess
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    // Representing some time consuming work.
                    Thread.Sleep(5000);
    
                    EventWaitHandle.OpenExisting("CHILD_PROCESS_READY")
                        .Set();
    
                    Process.GetProcessById(Convert.ToInt32(args[0]))
                        .WaitForExit();
                }
                catch (Exception exception)
                { }
            }
        }
    }
    

    【讨论】:

    • 这里最好的解决方案,但是你需要能够在子进程中添加一些代码。
    • 这是具有良好示例代码的正确解决方案。谢谢。
    【解决方案9】:

    为了扩展@ChrisG 的想法,请考虑使用 process.MainWindowHandle 并查看窗口消息循环是否响应。使用 p/invoke 这个 Win32 api:SendMessageTimeout。 从那个链接:

    如果函数成功,则返回 值非零。发送消息超时 不提供有关信息 如果个别窗口超时 使用 HWND_BROADCAST。

    如果函数失败或超时,返回值为0。获取 扩展错误信息,调用 获取上一个错误。如果 GetLastError 返回 ERROR_TIMEOUT,然后函数计时 出去。

    【讨论】:

      【解决方案10】:

      这里是一个使用System.Threading.Timer 的实现。可能有点出于它的目的。

          private static bool StartProcess(string filePath, string processName)
          {
              if (!File.Exists(filePath))
                  throw new InvalidOperationException($"Unknown filepath: {(string.IsNullOrEmpty(filePath) ? "EMPTY PATH" : filePath)}");
      
              var isRunning = false;
      
              using (var resetEvent = new ManualResetEvent(false))
              {
      
                  void Callback(object state)
                  {
                      if (!IsProcessActive(processName)) return;
                      isRunning = true;
                      // ReSharper disable once AccessToDisposedClosure
                      resetEvent.Set();
                  }
      
                  using (new Timer(Callback, null, 0, TimeSpan.FromSeconds(0.5).Milliseconds))
                  {
                      Process.Start(filePath);
                      WaitHandle.WaitAny(new WaitHandle[] { resetEvent }, TimeSpan.FromSeconds(9));
                  }
              }
      
              return isRunning;
          }
      
          private static bool StopProcess(string processName)
          {
              if (!IsProcessActive(processName)) return true;
      
              var isRunning = true;
      
              using (var resetEvent = new ManualResetEvent(false))
              {
      
                  void Callback(object state)
                  {
                      if (IsProcessActive(processName)) return;
                      isRunning = false;
                      // ReSharper disable once AccessToDisposedClosure
                      resetEvent.Set();
                  }
      
                  using (new Timer(Callback, null, 0, TimeSpan.FromSeconds(0.5).Milliseconds))
                  {
                      foreach (var process in Process.GetProcessesByName(processName))
                          process.Kill();
                      WaitHandle.WaitAny(new WaitHandle[] { resetEvent }, TimeSpan.FromSeconds(9));
                  }
              }
      
              return isRunning;
          }
      
          private static bool IsProcessActive(string processName)
          {
              return Process.GetProcessesByName(processName).Any();
          }
      

      【讨论】:

        【解决方案11】:
        public static class WinApi
        {
        
            [DllImport("user32.dll")]
            public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        
            public static class Windows
            {
                public const int NORMAL = 1;
                public const int HIDE = 0;
                public const int RESTORE = 9;
                public const int SHOW = 5;
                public const int MAXIMIXED = 3;
            }
        
        }
        

        应用程序

        String process_name = "notepad"
        Process process;
        process = Process.Start( process_name );
        
        while (!WinApi.ShowWindow(process.MainWindowHandle, WinApi.Windows.NORMAL))
        {
            Thread.Sleep(100);
            process.Refresh();
        }
        
        // Done!
        // Continue your code here ...
        

        【讨论】:

        • 不幸的是,这不适用于命令行进程...
        • @sɐunıɔןɐqɐp 当然它不适用于非接口进程,它们没有 MainWindowHandle。
        【解决方案12】:

        您还可以通过尝试以下方法来检查启动的进程是否响应: while(process.responding)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多