C# - 制作Process.Start等到进程启动

时间:2022-08-23 18:00:06

I need to make sure that a process is running before moving on with a method.

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

The statement is:

声明是:

Process.Start("popup.exe");

Can you do a WAIT command or set a delay on this value?

你能做一个WAIT命令或者设置这个值的延迟吗?

10 个解决方案

#1


106  

Do you mean wait until it's done? Then use Process.WaitForExit:

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

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

Alternatively, if it's an application with a UI that you are waiting to enter into a message loop, you can say:

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

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

Lastly, if neither of these apply, just Thread.Sleep for some reasonable amount of time:

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

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

#2


13  

I also needed this once, and I did a check on the window title of the process. If it is the one you expect, you can be sure the application is running. The application I was checking needed some time for startup and this method worked fine for me.

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

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

#3


9  

The answer of 'ChrisG' is correct, but we need to refresh MainWindowTitle every time and it's better to check for empty.... like this:

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

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

#4


7  

Like others have already said, it's not immediately obvious what you're asking. I'm going to assume that you want to start a process and then perform another action when the process "is ready".

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

Of course, the "is ready" is the tricky bit. Depending on what you're needs are, you may find that simply waiting is sufficient. However, if you need a more robust solution, you can consider using a named Mutex to control the control flow between your two processes.

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

For example, in your main process, you might create a named mutex and start a thread or task which will wait. Then, you can start the 2nd process. When that process decides that "it is ready", it can open the named mutex (you have to use the same name, of course) and signal to the first process.

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

#5


4  

I agree with Tom. In addition, to check the processes while performing Thread.Sleep, check the running processes. Something like:

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

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

    Thread.CurrentThread.Sleep(1000);
}

#6


4  

First of all: I know this is rather old but there still is not an accepted answer, so perhaps my approach will help someone else. :)

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

What I did to solve this is:

我做的是解决这个问题:

process.Start();

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

The association var time = process.StartTime will throw an exception as long as process did not start. So once it passes, it is safe to assume process is running and to work with it further. I am using this to wait for java process to start up, since it takes some time. This way it should be independent on what machine the application is running rather than using Thread.Sleep().

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

I understand this is not very clean solution, but the only one that should be performance independent I could think of.

我知道这不是一个非常干净的解决方案,但是我能想到的唯一应该是性能独立的解决方案。

#7


2  

Are you sure the Start method returns before the child process starts? I was always under the impression that Start starts the child process synchronously.

你确定在子进程启动之前返回Start方法吗?我一直认为Start会同步启动子进程。

If you want to wait until your child process finishes some sort of initialization then you need inter-process communication - see Interprocess communication for Windows in C# (.NET 2.0).

如果要等到子进程完成某种初始化,则需要进程间通信 - 请参阅C#(.NET 2.0)中的Windows进程间通信。

#8


1  

To extend @ChrisG's idea, a little, consider using process.MainWindowHandle and seeing if the window message loop is responding. Use p/invoke this Win32 api: SendMessageTimeout. From that link:

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

If the function succeeds, the return value is nonzero. SendMessageTimeout does not provide information about individual windows timing out if HWND_BROADCAST is used.

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

If the function fails or times out, the return value is 0. To get extended error information, call GetLastError. If GetLastError returns ERROR_TIMEOUT, then the function timed out.

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

#9


1  

I think what the OP may be referring to is the need to have a valid window handle from the child process so that he can process it in some way.

我认为OP可能指的是需要从子进程获得一个有效的窗口句柄,以便他可以以某种方式处理它。

In my case I want to spawn a Perl script to run in a DOS console window, and center the window on my forms application when it starts. If I grab Process.MainWindowHandle too early and call "MoveWindow" on it, the handle isn't valid yet and the call does nothing. If I wait a second (by calling Thread.Wait(1000)), the screen appears in its default location and suddenly moves after a second. Either can be quite annoying to the user.

在我的情况下,我想生成一个Perl脚本在DOS控制台窗口中运行,并在窗体应用程序启动时将窗口居中。如果我过早地抓住Process.MainWindowHandle并在其上调用“MoveWindow”,则句柄仍然无效且调用不执行任何操作。如果我等待一秒钟(通过调用Thread.Wait(1000)),屏幕将显示在其默认位置,并在一秒钟后突然移动。对用户来说可能非常烦人。

By going into a loop and waiting for "Process.MainWindowTitle" to return something meaningful, I can grab the window as soon as it's responsive and center it on my form without annoying flicker.

通过进入循环并等待“Process.MainWindowTitle”返回有意义的内容,我可以在响应时立即抓住窗口并将其置于我的表单中,而不会产生恼人的闪烁。

The OP may be trying to do something similar.

OP可能正在尝试做类似的事情。

#10


0  

Here an implementation that uses a System.Threading.Timer. Maybe a bit much for its purpose.

这是一个使用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


106  

Do you mean wait until it's done? Then use Process.WaitForExit:

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

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

Alternatively, if it's an application with a UI that you are waiting to enter into a message loop, you can say:

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

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

Lastly, if neither of these apply, just Thread.Sleep for some reasonable amount of time:

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

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

#2


13  

I also needed this once, and I did a check on the window title of the process. If it is the one you expect, you can be sure the application is running. The application I was checking needed some time for startup and this method worked fine for me.

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

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

#3


9  

The answer of 'ChrisG' is correct, but we need to refresh MainWindowTitle every time and it's better to check for empty.... like this:

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

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

#4


7  

Like others have already said, it's not immediately obvious what you're asking. I'm going to assume that you want to start a process and then perform another action when the process "is ready".

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

Of course, the "is ready" is the tricky bit. Depending on what you're needs are, you may find that simply waiting is sufficient. However, if you need a more robust solution, you can consider using a named Mutex to control the control flow between your two processes.

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

For example, in your main process, you might create a named mutex and start a thread or task which will wait. Then, you can start the 2nd process. When that process decides that "it is ready", it can open the named mutex (you have to use the same name, of course) and signal to the first process.

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

#5


4  

I agree with Tom. In addition, to check the processes while performing Thread.Sleep, check the running processes. Something like:

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

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

    Thread.CurrentThread.Sleep(1000);
}

#6


4  

First of all: I know this is rather old but there still is not an accepted answer, so perhaps my approach will help someone else. :)

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

What I did to solve this is:

我做的是解决这个问题:

process.Start();

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

The association var time = process.StartTime will throw an exception as long as process did not start. So once it passes, it is safe to assume process is running and to work with it further. I am using this to wait for java process to start up, since it takes some time. This way it should be independent on what machine the application is running rather than using Thread.Sleep().

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

I understand this is not very clean solution, but the only one that should be performance independent I could think of.

我知道这不是一个非常干净的解决方案,但是我能想到的唯一应该是性能独立的解决方案。

#7


2  

Are you sure the Start method returns before the child process starts? I was always under the impression that Start starts the child process synchronously.

你确定在子进程启动之前返回Start方法吗?我一直认为Start会同步启动子进程。

If you want to wait until your child process finishes some sort of initialization then you need inter-process communication - see Interprocess communication for Windows in C# (.NET 2.0).

如果要等到子进程完成某种初始化,则需要进程间通信 - 请参阅C#(.NET 2.0)中的Windows进程间通信。

#8


1  

To extend @ChrisG's idea, a little, consider using process.MainWindowHandle and seeing if the window message loop is responding. Use p/invoke this Win32 api: SendMessageTimeout. From that link:

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

If the function succeeds, the return value is nonzero. SendMessageTimeout does not provide information about individual windows timing out if HWND_BROADCAST is used.

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

If the function fails or times out, the return value is 0. To get extended error information, call GetLastError. If GetLastError returns ERROR_TIMEOUT, then the function timed out.

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

#9


1  

I think what the OP may be referring to is the need to have a valid window handle from the child process so that he can process it in some way.

我认为OP可能指的是需要从子进程获得一个有效的窗口句柄,以便他可以以某种方式处理它。

In my case I want to spawn a Perl script to run in a DOS console window, and center the window on my forms application when it starts. If I grab Process.MainWindowHandle too early and call "MoveWindow" on it, the handle isn't valid yet and the call does nothing. If I wait a second (by calling Thread.Wait(1000)), the screen appears in its default location and suddenly moves after a second. Either can be quite annoying to the user.

在我的情况下,我想生成一个Perl脚本在DOS控制台窗口中运行,并在窗体应用程序启动时将窗口居中。如果我过早地抓住Process.MainWindowHandle并在其上调用“MoveWindow”,则句柄仍然无效且调用不执行任何操作。如果我等待一秒钟(通过调用Thread.Wait(1000)),屏幕将显示在其默认位置,并在一秒钟后突然移动。对用户来说可能非常烦人。

By going into a loop and waiting for "Process.MainWindowTitle" to return something meaningful, I can grab the window as soon as it's responsive and center it on my form without annoying flicker.

通过进入循环并等待“Process.MainWindowTitle”返回有意义的内容,我可以在响应时立即抓住窗口并将其置于我的表单中,而不会产生恼人的闪烁。

The OP may be trying to do something similar.

OP可能正在尝试做类似的事情。

#10


0  

Here an implementation that uses a System.Threading.Timer. Maybe a bit much for its purpose.

这是一个使用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();
    }