C # - Створення процесу. Почніть чекати, поки процес не запуститься


77

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

Заява така:

Process.Start("popup.exe");

Чи можете ви виконати команду WAIT або встановити затримку цього значення?


Що означає "переконатись"? У popup.exe повинна бути конкретна річ, яка вам потрібна, правда? Якщо так, то очікування запуску буде недостатньо.
Ед Байятес,

Також у вас є контроль над popup.exe? Значення, чи можете ви додати до нього код, щоб сигналізувати про процес нересту, що він запущений?
Ед Байятес,

Відповіді:


137

Ви маєте на увазі почекати, поки це буде зроблено? Потім використовуйте 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

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 Іншими словами ... Саме того, що хоче ОП?
Basic

@Basic Це довідковий веб-сайт, і цю відповідь можуть прочитати люди, які не є ОП.
Eagle-Eye

@ Eagle-Eye Я не впевнений, що розумію вашу думку? ta.speoit.is (ні OP для Q, ні A) передбачало, що функція не працює, як рекламується. Я перевірив документацію, і виявилося, що він робить саме те, що вимагав ОП. Яким чином це зробило сайт менш корисним для майбутніх відвідувачів?
Basic

18

Мені це теж потрібно було одного разу, і я перевірив назву вікна процесу. Якщо це той, який ви очікуєте, ви можете бути впевнені, що додаток запущений. Програмі, яку я перевіряв, знадобився певний час для запуску, і цей метод у мене справно працював.

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

15

Відповідь "ChrisG" правильна, але нам потрібно кожен раз оновлювати MainWindowTitle, і краще перевірити, чи немає порожніх .... ось так:

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

2
Чи можемо ми припустити, що після того, як програма командного рядка отримала заголовок, вона була запущена?
Джек

1
Я додав додаткову перевірку в той час як заяву: proc.HasExited
Ванги

9

Перш за все: я знаю, що це досить давно, але досі немає прийнятої відповіді, тому, можливо, мій підхід допоможе комусь іншому. :)

Я вирішив це:

process.Start();

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

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

Я розумію, що це не дуже чисте рішення, але єдине, яке повинно бути незалежним від продуктивності, я міг придумати.


1
Як би це не було шалено, це здається найпростішим способом отримати необхідну інформацію.
Артуро Торрес Санчес

7

Як вже говорили інші, не одразу очевидно, про що ви питаєте. Я збираюся припустити, що ви хочете запустити процес, а потім виконати іншу дію, коли процес "буде готовий".

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

Наприклад, у вашому основному процесі ви можете створити іменований мьютекс і запустити ланцюжок чи завдання, які будуть чекати. Потім ви можете розпочати 2-й процес. Коли цей процес вирішить, що "він готовий", він може відкрити названий мьютекс (звичайно, потрібно використовувати те саме ім'я) і подати сигнал першому процесу.


Це саме те, що я очікував знайти, коли шукав це. Дякую.
Ніколас Міллер

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 миль і вийти з циклу, якщо процес не буде знайдений.
Джек,

2

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

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


1

Щоб трохи розширити ідею @ ChrisG, розгляньте можливість використання process.MainWindowHandle та перевірити, чи відповідає цикл віконного повідомлення. Використовуйте p / викликати цей API Win32: SendMessageTimeout . За цим посиланням:

Якщо функція успішна, повертається значення ненульове. SendMessageTimeout не надає інформації про тайм-аут окремих вікон, якщо використовується HWND_BROADCAST.

Якщо функція виходить з ладу або закінчується час очікування, повертається значення 0. Щоб отримати розширену інформацію про помилку, зателефонуйте GetLastError. Якщо GetLastError повертає ERROR_TIMEOUT, тоді функція минула.


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

Тут реалізація, яка використовує a 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();
    }

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)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.