C#-创建一个Process.Start等待直到该进程启动


76

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

该语句是:

Process.Start("popup.exe");

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


“确保”是什么意思?您必须在popup.exe中运行特定的内容,对不对?如果是这样,仅等待它运行还不够。
Ed Bayiates

您还可以控制popup.exe吗?意思是您可以向其中添加代码以指示生成过程正在运行吗?
Ed Bayiates

Answers:


136

你是说等到完成了吗?然后使用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

1
在你的第一个片段,你必须手动调用process.Start()之前process.WaitForExit(); 否则将引发异常。
Bala R

9
只要确保您了解WaitForInputIdle的实际功能,即可blogs.msdn.com/b/oldnewthing/archive/2010/03/25/9984720.aspx
ta.speot.is

1
@ ta.speot.is换句话说......究竟该OP想要什么?
2015年

@Basic这是参考网站,不是OP的人可能会阅读此答案。
鹰眼

@ Eagle-Eye我不确定我是否理解你的观点?ta.speoit.is(Q或A的OP均未暗示)该功能无法像所宣传的那样起作用。我检查了文档,它似乎完全符合OP的要求。以什么方式使网站对将来的访问者失去了用处?
基本的

18

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

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

14

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

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

2
我们是否可以假定命令行应用程序一旦获得标题就启动了?
2016年

1
我在while语句中添加了一个附加检查:!proc.HasExited
Vangi

9

首先:我知道这已经很老了,但是仍然没有一个可以接受的答案,所以也许我的方法会对别人有所帮助。:)

为了解决这个问题,我要做的是:

process.Start();

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

var time = process.StartTime只要进程未启动,关联将引发异常。因此,一旦通过,可以安全地假定进程正在运行并进一步进行处理。我用它来等待Java进程启动,因为这需要一些时间。这样,它应该独立于应用程序正在运行的计算机,而不是使用Thread.Sleep()

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


1
尽管如此,但它似乎是获取所需信息的最直接方法。
Arturo TorresSánchez17年

7

就像其他人已经说过的那样,您要问的不是立即显而易见的。我将假设您要启动一个过程,然后在过程“准备就绪”时执行另一个操作。

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

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


这正是我进行搜索时所期望的。谢谢。
Nicholas Miller

4

我同意汤姆。另外,要在执行Thread.Sleep时检查进程,请检查正在运行的进程。就像是:

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

    Thread.CurrentThread.Sleep(1000);
}

2
while (!Process.GetProcesses().Any(p=>p.Name == myName)) { Thread.Sleep(100); }
dss539

为什么不GetProcessesByName()呢?while(Process.GetProcessesByName(myName).Length == 0) { Thread.Sleep(100); }尽管它可能大部分时间都起作用,但是正确的方法是等到n毫秒,如果找不到该进程,则退出循环。
杰克


1

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

如果函数成功,则返回值为非零。如果使用HWND_BROADCAST,则SendMessageTimeout不提供有关各个窗口超时的信息。

如果函数失败或超时,则返回值为0。要获取扩展的错误信息,请调用GetLastError。如果GetLastError返回ERROR_TIMEOUT,则函数超时。


1

这里是使用的实现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();
    }

1

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

父流程:

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)
            { }
        }
    }
}

3
最好的解决方案,但是您需要能够在子进程中添加一些代码。
ViRuSTriNiTy

0
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 ...

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.