101 votes

Comment redémarrer mon application C# WinForm ?

Développement d'une application WinForm en C# .NET 2.0. J'ai besoin que l'application se ferme et redémarre d'elle-même.

Application.Restart();

La méthode ci-dessus a dont il est prouvé qu'il n'est pas fiable .

Quelle est la meilleure façon de redémarrer l'application ?

3 votes

Je suis curieux de savoir s'il faut redémarrer votre application. Je n'ai jamais pensé à ce besoin auparavant. Quelles sont vos circonstances ?

1 votes

Notre cas particulier : une application de lecteur multimédia qui est censée faire tourner en boucle des images et du contenu flash. Elle doit fonctionner pendant des jours et des jours sans redémarrage de la machine, et il n'y a pas de clavier/souris, donc aucune interaction avec l'utilisateur. Si le programme se bloque (exception non gérée), il doit redémarrer le programme, et non sortir ou afficher une erreur. stackoverflow.com/questions/773768/ C'est la raison pour laquelle le programme continue d'avoir des exceptions que je ne peux pas empêcher. :(

2 votes

Finalement, une solution bien meilleure pour notre application a été de développer une petite application Watchdog qui est lancée (si elle n'est pas déjà en cours d'exécution) à partir de l'application principale. Le chien de garde vérifie simplement toutes les 10 secondes environ si l'application principale a encore un processus en cours d'exécution, et si ce n'est pas le cas, il en démarre un. Simple, élégant, et beaucoup plus robuste que d'essayer de redémarrer à partir de l'application principale.

107voto

EMP Points 17246

Une approche beaucoup plus simple qui a fonctionné pour moi est la suivante :

Application.Restart();
Environment.Exit(0);

Cela préserve les arguments de la ligne de commande et fonctionne malgré les gestionnaires d'événements qui empêcheraient normalement la fermeture de l'application.

L'appel Restart() tente de sortir, démarre quand même une nouvelle instance et revient. L'appel Exit() met ensuite fin au processus sans donner la chance aux gestionnaires d'événements de s'exécuter. Il y a une très brève période pendant laquelle les deux processus sont en cours d'exécution, ce qui n'est pas un problème dans mon cas, mais peut-être dans d'autres cas.

Le code de sortie 0 dans Environment.Exit(0); spécifie un arrêt propre. Vous pouvez également quitter avec 1 pour spécifier qu'une erreur s'est produite.

1 votes

Simple, mais fiable. Cela devrait être la réponse acceptée. J'essayais d'implémenter une fonction de déconnexion qui viderait toutes les variables globales et donnerait l'impression que l'application vient de démarrer. J'allais simplement afficher le panneau de connexion et remettre à zéro toutes les variables globales qui contiennent des informations importantes de la base de données. Cette solution m'a rendu la vie beaucoup plus simple. Merci !

0 votes

System.Windows.Forms.Application.Restart() fonctionne également pour les applications WPF. Testé avec le système d'exploitation Windows 10.

0 votes

Whaaaat ?! Vous plaisantez... n'est-ce pas ? C# <3. Gardez à l'esprit que, par défaut, ceci ne lève pas OnClose() les événements du formulaire et autres.

58voto

Darqer Points 776

Si vous êtes dans le formulaire de l'application principale, essayez d'utiliser

System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app

7 votes

Il est similaire, mais différent. Application.Exit n'a pas fonctionné pour moi, et this.Close() a fait le travail.

1 votes

Mai Enviorment.Exit(0) fera également l'affaire.

2 votes

Enviorment.Exit est une sortie sale et assez envahissante car elle empêche le code de nettoyage de l'application de s'exécuter. Ce n'est pas le bon choix la plupart du temps.

42voto

HiredMind Points 824

Malheureusement, vous ne pouvez pas utiliser Process.Start() pour démarrer une instance du processus en cours d'exécution. Selon la documentation de Process.Start() : "Si le processus est déjà en cours d'exécution, aucune ressource de processus supplémentaire n'est démarrée..."

Cette technique fonctionnera parfaitement sous le débogueur VS (parce que VS fait une sorte de magie qui fait croire à Process.Start que le processus n'est pas déjà en cours d'exécution), mais échouera si elle n'est pas exécutée sous le débogueur. (Notez que cela peut être spécifique au système d'exploitation - je crois me souvenir que dans certains de mes tests, cela a fonctionné sous XP ou Vista, mais je me souviens peut-être seulement de l'avoir exécuté sous le débogueur).

Cette technique est exactement celle utilisée par le dernier programmeur du projet sur lequel je travaille actuellement, et j'essaie de trouver une solution de contournement depuis un certain temps. Jusqu'à présent, je n'ai trouvé qu'une seule solution, qui me semble sale et peu pratique : lancer une deuxième application, qui attend en arrière-plan que la première application se termine, puis relance la première application. Je suis sûr que ça pourrait fonctionner, mais, beurk.

Edit : Utiliser une 2ème application fonctionne. Tout ce que j'ai fait dans la seconde application était :

    static void RestartApp(int pid, string applicationName )
    {
        // Wait for the process to terminate
        Process process = null;
        try
        {
            process = Process.GetProcessById(pid);
            process.WaitForExit(1000);
        }
        catch (ArgumentException ex)
        {
            // ArgumentException to indicate that the 
            // process doesn't exist?   LAME!!
        }
        Process.Start(applicationName, "");
    }

(Il s'agit d'un exemple très simplifié. Le vrai code comporte de nombreux contrôles d'intégrité, de gestion des erreurs, etc.)

0 votes

Je suis d'accord avec HiredMind, et j'ai moi-même opté pour la même implémentation du "programme de surveillance" peu après avoir écrit la réponse. Désolé, j'aurais dû revenir ici et mettre à jour. Je ne pense pas qu'il devrait se sentir trop horriblement laid, sale et dégoûtant. Le modèle de programme Watchdog est assez largement utilisé.

0 votes

Vous n'avez pas réellement besoin d'une seconde application sur le disque... vous pourriez utiliser un script et le générer à la volée avec un nom temporaire... Je pense que cela pourrait atténuer votre sentiment de culpabilité d'avoir une deuxième application pour le plaisir de redémarrer la vôtre... Ou vous pourriez "émettre" une application C# entière, la compiler, la sauvegarder sur le disque et l'exécuter (sale, sale pensée)...

0 votes

Le premier paragraphe n'est pas correct : Process.Start ne regarde pas la liste des processus du système d'exploitation en cours. L'énoncé de cette documentation ne parle que de cela instance objet de la Process classe. Le site Process peut être attachée à un processus en cours d'exécution, mais elle peut aussi être dans un état non démarré. À mon avis, il s'agit d'une erreur de conception. La meilleure pratique, IMO, est de ne jamais réutiliser une classe Process et de la lancer immédiatement après sa création. Idéalement, utilisez l'option statique Process.Start méthode. Ensuite, cette documentation et ce défaut de conception n'entrent jamais en jeu.

18voto

Robin Van Persi Points 5197

Je suis peut-être en retard, mais voici ma solution simple, qui fonctionne à merveille avec toutes les applications dont je dispose :

        try
        {
            //run the program again and close this one
            Process.Start(Application.StartupPath + "\\blabla.exe"); 
            //or you can use Application.ExecutablePath

            //close this one
            Process.GetCurrentProcess().Kill();
        }
        catch
        { }

0 votes

Fonctionne très bien sur Win-7-x64 et Win-XP-x32. Je ne vois rien à propos d'une quelconque contrainte dans les docs . Cela devrait être la réponse acceptée.

0 votes

@Bitterblue Le lien vers les docs que vous avez posté indique "Si le processus est déjà en cours d'exécution, aucune ressource de processus supplémentaire n'est lancée." C'est la 3ème ligne dans la section des remarques. J'aurais aimé que ce ne soit pas le cas, mais ça l'est.

0 votes

@HiredMind Je suppose que nous pourrions discuter de ce que "contraintes" signifie pour chacun d'entre nous. Mais la section est intitulée "Remarques" et non "Contraintes". Je peux donc m'en accommoder. Et pourquoi souhaite ce n'était pas comme ça ? Avez-vous eu des problèmes avec ça ? Parce que moi non. Ça marche parfaitement pour moi.

15voto

JohnIdol Points 16355

J'ai eu exactement le même problème et j'avais moi aussi l'obligation d'empêcher les instances dupliquées - je propose une solution alternative à celle de HiredMind (qui fonctionnera très bien).

Ce que je fais, c'est démarrer le nouveau processus avec le processId de l'ancien processus (celui qui déclenche le redémarrage) comme argument de ligne de commande :

// Shut down the current app instance.
Application.Exit();

// Restart the app passing "/restart [processId]" as cmd line args
Process.Start(Application.ExecutablePath, "/restart" + Process.GetCurrentProcess().Id);

Ensuite, lorsque la nouvelle application démarre, j'analyse d'abord les arguments de la ligne cm et je vérifie si le drapeau de redémarrage est présent avec un processId, puis j'attends que le processus se termine :

if (_isRestart)
{
   try
   {
      // get old process and wait UP TO 5 secs then give up!
      Process oldProcess = Process.GetProcessById(_restartProcessId);
      oldProcess.WaitForExit(5000);
   }
   catch (Exception ex)
   { 
      // the process did not exist - probably already closed!
      //TODO: --> LOG
   }
}

Je ne montre évidemment pas tous les contrôles de sécurité que j'ai mis en place, etc.

Même si ce n'est pas idéal, je trouve que c'est une alternative valable pour ne pas avoir à mettre en place une application séparée juste pour gérer le redémarrage.

1 votes

Il existe, à mon avis, une solution plus efficace à ce problème. J'ai également besoin d'avoir une seule instance et de permettre à l'utilisateur de redémarrer l'application (par exemple lorsqu'elle se plante). J'ai failli mettre en œuvre votre solution, mais il m'est apparu qu'il serait préférable d'ajouter simplement un argument de ligne de commande différent, à savoir permet à plusieurs instances à exécuter.

0 votes

Mmm, tu inverses la logique - j'aime ça ! Le seul problème est que si quelqu'un trouve l'argument de la ligne de commande qui permet des instances multiples, des choses étranges pourraient se produire :D

0 votes

J'ai eu la chance qu'il s'agisse d'une fonctionnalité que les utilisateurs avaient demandée, donc c'était gagnant-gagnant. Je préférerais qu'ils "trouvent" un /allowMultipleInstances que le plutôt étrange /restart un.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X