C # - Заставить Process.Start ждать, пока процесс не запустится - PullRequest
67 голосов
/ 17 июня 2011

Мне нужно убедиться, что процесс запущен, прежде чем перейти к методу.

Заявление:

Process.Start("popup.exe");

Можете ли вы выполнить команду WAIT или установить задержку для этого значения?

Ответы [ 9 ]

119 голосов
/ 17 июня 2011

Вы имеете в виду подождать, пока это не будет сделано? Тогда используйте Process.WaitForExit:

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

В качестве альтернативы, если это приложение с пользовательским интерфейсом, которое вы ожидаете ввести в цикл сообщений, вы можете сказать:

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

Наконец, если ни один из них не применим, просто Thread.Sleep в течение некоторого разумного промежутка времени:

process.Start();
Thread.Sleep(1000); // sleep for one second
14 голосов
/ 17 июня 2011

Мне это тоже нужно было один раз, и я проверил заголовок окна процесса. Если это тот, который вы ожидаете, вы можете быть уверены, что приложение работает. Приложению, которое я проверял, требовалось некоторое время для запуска, и этот метод отлично работал для меня.

var process = Process.Start("popup.exe");
while(process.MainWindowTitle != "Title")
{
    Thread.Sleep(10);
}
11 голосов
/ 04 марта 2016

Ответ 'ChrisG' правильный, но нам нужно каждый раз обновлять MainWindowTitle, и лучше проверять на пустое .... как это:

var proc = Process.Start("popup.exe");
while (string.IsNullOrEmpty(proc.MainWindowTitle))
{
    System.Threading.Thread.Sleep(100);
    proc.Refresh();
}
7 голосов
/ 23 марта 2017

Прежде всего: я знаю, что это довольно старый, но до сих пор нет принятого ответа, поэтому, возможно, мой подход поможет кому-то еще. :)

Что я сделал, чтобы решить это:

process.Start();

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

Ассоциация var time = process.StartTime вызовет исключение, если процесс не запустился. Поэтому, как только он пройдет, можно с уверенностью предположить, что процесс запущен, и продолжить работу с ним. Я использую это, чтобы дождаться запуска процесса Java, так как это занимает некоторое время. Таким образом, он должен зависеть от того, на какой машине запущено приложение, а не на Thread.Sleep().

.

Я понимаю, что это не очень чистое решение, но единственное, которое должно быть независимым от производительности, о котором я мог подумать.

7 голосов
/ 17 июня 2011

Как уже говорили другие, не сразу понятно, о чем вы спрашиваете. Я собираюсь предположить, что вы хотите запустить процесс, а затем выполнить другое действие, когда процесс «готов».

Конечно, "готов" - хитрый момент. В зависимости от того, что вам нужно, вы можете обнаружить, что достаточно просто ожидания. Однако, если вам нужно более надежное решение, вы можете рассмотреть использование именованного Mutex для управления потоком управления между вашими двумя процессами.

Например, в вашем основном процессе вы можете создать именованный мьютекс и запустить поток или задачу, которая будет ожидать. Затем вы можете начать 2-й процесс. Когда этот процесс решает, что «он готов», он может открыть именованный мьютекс (конечно, вы должны использовать то же имя) и дать сигнал первому процессу.

4 голосов
/ 17 июня 2011

Я согласен с Томом. Кроме того, чтобы проверить процессы при выполнении Thread.Sleep, проверьте запущенные процессы. Что-то вроде:

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

    Thread.CurrentThread.Sleep(1000);
}
2 голосов
/ 17 июня 2011

Вы уверены, что метод Start возвращается до запуска дочернего процесса?У меня всегда было впечатление, что Start запускает дочерний процесс синхронно.

Если вы хотите подождать, пока ваш дочерний процесс завершит какую-то инициализацию, тогда вам нужно межпроцессное взаимодействие - см. Межпроцессное взаимодействие для Windows в C # (.NET 2.0) .

1 голос
/ 17 июня 2011

Чтобы немного расширить идею @ ChrisG, рассмотрите использование process.MainWindowHandle и посмотрите, отвечает ли цикл сообщения окна. Используйте p / invoke этого Win32 API: SendMessageTimeout . По этой ссылке:

Если функция завершается успешно, возврат значение ненулевое. SendMessageTimeout не предоставляет информацию о время ожидания отдельных окон, если HWND_BROADCAST используется.

Если функция не работает или время ожидания истекло, возвращаемое значение равно 0. Чтобы получить расширенная информация об ошибках, вызов GetLastError. Если GetLastError возвращает ERROR_TIMEOUT, то функция приурочена вне.

0 голосов
/ 14 июня 2018

Здесь реализация, которая использует 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();
    }
...