web-dev-qa-db-fra.com

C # - Making a Process.Start attendre le démarrage du processus

Je dois m'assurer qu'un processus est en cours d'exécution avant de passer à une méthode.

La déclaration est la suivante:

Process.Start("popup.exe");

Pouvez-vous faire une commande WAIT ou définir un délai sur cette valeur?

61
Tom

Voulez-vous dire attendre jusqu'à ce que ce soit fait? Ensuite, utilisez Process.WaitForExit:

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

Sinon, s'il s'agit d'une application avec une interface utilisateur que vous attendez pour entrer dans une boucle de message, vous pouvez dire:

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

Enfin, si aucun de ces cas ne s’applique, il suffit de Thread.Sleep pour une durée raisonnable:

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

J'avais aussi besoin de cela une fois et j'ai vérifié le titre de la fenêtre du processus. Si c'est ce que vous attendez, vous pouvez être sûr que l'application est en cours d'exécution. L'application que je vérifiais avait besoin d'un peu de temps pour le démarrage et cette méthode fonctionnait parfaitement pour moi.

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

La réponse de 'ChrisG' est correcte, mais nous devons actualiser MainWindowTitle à chaque fois et il est préférable de vérifier si vide ... comme ceci:

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

Comme d'autres l'ont déjà dit, ce que vous demandez n'est pas immédiatement évident. Je vais supposer que vous souhaitez démarrer un processus, puis effectuer une autre action lorsque le processus "est prêt". 

Bien sûr, le "est prêt" est la partie la plus délicate. Selon vos besoins, il vous suffira peut-être d'attendre. Toutefois, si vous avez besoin d’une solution plus robuste, vous pouvez envisager d’utiliser un Mutex pour contrôler le flux de contrôle entre vos deux processus.

Par exemple, dans votre processus principal, vous pouvez créer un mutex nommé et démarrer un thread ou une tâche qui attendra. Ensuite, vous pouvez commencer le deuxième processus. Lorsque ce processus décide qu'il est "prêt", il peut ouvrir le mutex nommé (vous devez utiliser le même nom, bien sûr) et signaler au premier processus.

7
Matt

Tout d'abord: je sais que c'est assez ancien, mais il n'y a toujours pas de réponse acceptée, alors peut-être que mon approche aidera quelqu'un d'autre. :) 

Ce que j'ai fait pour résoudre ceci est:

process.Start();

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

L'association var time = process.StartTime lève une exception tant que le processus n'a pas démarré. Ainsi, une fois le processus passé, il est prudent de supposer que le processus est en cours d'exécution et de le poursuivre. J'utilise ceci pour attendre le démarrage du processus Java, car cela prend un certain temps. De cette façon, il devrait être indépendant de la machine exécutée par l'application plutôt que d'utiliser Thread.Sleep().

Je comprends que ce n'est pas une solution très propre, mais le seul qui devrait être indépendant de la performance, je pourrais penser.

5
RhodryCZ

Je suis d'accord avec Tom. De plus, pour vérifier les processus lors de l'exécution de Thread.Sleep, vérifiez les processus en cours d'exécution. Quelque chose comme:

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

    Thread.CurrentThread.Sleep(1000);
}
4
Frank Pearson

Êtes-vous sûr que la méthode Start est renvoyée avant le démarrage du processus enfant? J'ai toujours eu l'impression que Start lance le processus enfant de manière synchrone.

Si vous souhaitez attendre que votre processus enfant ait terminé une sorte d'initialisation, vous avez besoin d'une communication entre processus - voir Communication interprocess pour Windows en C # (.NET 2.0).

2
Jakub Konecki

Pour élargir un peu l'idée de @ ChrisG, envisagez d'utiliser process.MainWindowHandle pour voir si la boucle de message de fenêtre répond. Utilisez p/invoke cette api Win32: SendMessageTimeout . À partir de ce lien:

Si la fonction réussit, le retour la valeur est non nulle. SendMessageTimeout ne fournit pas d'informations sur fenêtres individuelles chronométrant si HWND_BROADCAST est utilisé.

Si la fonction échoue ou expire, la valeur de retour est 0. Pour obtenir information d'erreur étendue, appelez GetLastError. Si GetLastError est renvoyé ERROR_TIMEOUT, puis la fonction a chronométré en dehors.

1
agent-j

Voici une implémentation qui utilise un System.Threading.Timer. Peut-être un peu beaucoup pour son but.

    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
Peter