Como faço para reiniciar meu aplicativo c # WinForm?

Desenvolvendo um aplicativo WinForm do C # .NET 2.0. Precisa que o aplicativo feche e reinicie.

Application.Restart(); 

O método acima provou não ser confiável .

Qual é a melhor maneira de reiniciar o aplicativo?

Infelizmente você não pode usar Process.Start () para iniciar uma instância do processo atualmente em execução. De acordo com a documentação do Process.Start (): “Se o processo já estiver em execução, nenhum recurso de processo adicional será iniciado …”

Essa técnica funcionará bem no depurador do VS (porque o VS faz algum tipo de mágica que faz o Process.Start pensar que o processo ainda não está em execução), mas falhará quando não for executado no depurador. (Note que isso pode ser específico do sistema operacional – pareço lembrar que, em alguns dos meus testes, ele funcionava no XP ou no Vista, mas eu posso estar apenas lembrando de executá-lo sob o depurador.)

Essa técnica é exatamente a usada pelo último programador no projeto no qual estou trabalhando atualmente, e estou tentando encontrar uma solução alternativa para isso há algum tempo. Até agora, eu só encontrei uma solução, e ela parece suja e desajeitada para mim: inicie uma segunda aplicação, que aguarda em segundo plano para que a primeira aplicação termine e, em seguida, reinicie a primeira aplicação. Tenho certeza que funcionaria, mas, sim.

Edit: Usando um segundo aplicativo funciona. Tudo o que fiz no segundo aplicativo foi:

  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, ""); } 

(Este é um exemplo muito simplificado. O código real tem muita verificação de sanidade, tratamento de erros, etc)

Se você estiver no formulário principal do aplicativo, tente usar

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

Uma abordagem muito mais simples que funcionou para mim é:

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

Isso preserva os argumentos da linha de comando e funciona apesar dos manipuladores de events que normalmente impediriam o fechamento do aplicativo.

A chamada Restart () tenta sair, inicia uma nova instância e retorna. A chamada Exit () encerra o processo sem dar a nenhum manipulador de events a chance de executar. Há um período muito breve em que ambos os processos estão em execução, o que não é um problema no meu caso, mas talvez em outros casos.

O código de saída 0 em Environment.Exit(0); especifica um desligamento limpo. Você também pode sair com 1 para especificar um erro.

Eu posso estar atrasado para a festa, mas aqui está a minha solução simples e funciona como um encanto em todas as aplicações que tenho:

  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 { } 

Eu tive o mesmo problema exato e também tive um requisito para evitar instâncias duplicadas – proponho uma solução alternativa para a que o HiredMind está propondo (que funcionará bem).

O que estou fazendo é iniciar o novo processo com o processId do processo antigo (aquele que aciona a reboot) como um argumento de linha cmd:

 // 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); 

Então, quando o novo aplicativo é iniciado, primeiro analiso os args da linha cm e verifico se o sinalizador de reboot está lá com um processId e, em seguida, aguarde o processo para Sair:

 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 } } 

Eu obviamente não estou mostrando todas as verificações de segurança que tenho no lugar, etc.

Mesmo se não for o ideal – eu acho isso uma alternativa válida para que você não tenha que ter um aplicativo separado apenas para lidar com o reinício.

É simples, você só precisa chamar os methods Application.Restart() que tende a invocar seu aplicativo para ser reiniciado. Mas você deve ter que sair do ambiente Local com seus códigos de erro:

 Application.Restart(); Environment.exit(int errorcode); 

você pode criar uma enumeração de código de erro para que você possa usá-lo com eficiência.
Outro método é simplesmente sair do aplicativo e iniciar o processo com o caminho do executável:

 Application.exit(); System.Diagnostics.Process.Start(Application.ExecutablePath); 

Iniciar / Sair do Método

 // Get the parameters/arguments passed to program if any string arguments = string.Empty; string[] args = Environment.GetCommandLineArgs(); for (int i = 1; i < args.Length; i++) // args[0] is always exe path/filename arguments += args[i] + " "; // Restart current application, with same arguments/parameters Application.Exit(); System.Diagnostics.Process.Start(Application.ExecutablePath, arguments); 

Isso parece funcionar melhor que Application.Restart ();

Não tenho certeza de como isso funciona se o seu programa proteger contra várias instâncias. Meu palpite é que seria melhor você lançar um segundo .exe que faz uma pausa e, em seguida, inicia o aplicativo principal para você.

Experimente este código:

 bool appNotRestarted = true; 

Este código também deve estar na function:

 if (appNotRestarted == true) { appNotRestarted = false; Application.Restart(); Application.ExitThread(); } 

Eu descobri uma outra solução, talvez qualquer um possa usá-la também.

 string batchContent = "/c \"@ECHO OFF & timeout /t 6 > nul & start \"\" \"$[APPPATH]$\" & exit\""; batchContent = batchContent.Replace("$[APPPATH]$", Application.ExecutablePath); Process.Start("cmd", batchContent); Application.Exit(); 

O código é simplificado, então cuide das exceções e outras coisas;)

Você está esquecendo as opções / parâmetros da linha de comando que foram passados ​​para sua instância atualmente em execução. Se você não passar, você não está fazendo uma reboot real. Configure o Process.StartInfo com um clone dos parâmetros do seu processo e, em seguida, inicie.

Por exemplo, se o seu processo foi iniciado como myexe -f -nosplash myfile.txt , seu método só executaria myexe sem todos esses sinalizadores e parâmetros.

Eu queria que o novo aplicativo fosse iniciado depois que o antigo fosse desligado.

Usando process.WaitForExit () para esperar o seu próprio processo para o desligamento não faz sentido. Sempre será o tempo limite.

Então, minha abordagem é usar Application.Exit () e depois esperar, mas permitir que os events sejam processados, por um período de tempo. Em seguida, inicie um novo aplicativo com os mesmos argumentos do antigo.

 static void restartApp() { string commandLineArgs = getCommandLineArgs(); string exePath = Application.ExecutablePath; try { Application.Exit(); wait_allowingEvents( 1000 ); } catch( ArgumentException ex ) { throw; } Process.Start( exePath, commandLineArgs ); } static string getCommandLineArgs() { Queue args = new Queue( Environment.GetCommandLineArgs() ); args.Dequeue(); // args[0] is always exe path/filename return string.Join( " ", args.ToArray() ); } static void wait_allowingEvents( int durationMS ) { DateTime start = DateTime.Now; do { Application.DoEvents(); } while( start.Subtract( DateTime.Now ).TotalMilliseconds > durationMS ); } 

Você também pode usar o Restarter .

O Restarter é um aplicativo que monitora e reinicia automaticamente programas e aplicativos paralisados ​​ou travados. Ele foi originalmente desenvolvido para monitorar e reiniciar servidores de jogos, mas fará o trabalho de qualquer programa ou aplicativo baseado em console ou formulário.

 public static void appReloader() { //Start a new instance of the current program Process.Start(Application.ExecutablePath); //close the current application process Process.GetCurrentProcess().Kill(); } 

Application.ExecutablePath retorna o caminho do arquivo .exe do seu aplicativo Por favor, siga a ordem das chamadas. Você pode querer colocá-lo em uma cláusula try-catch.

Aqui estão meus 2 centavos:

A sequência Start New Instance-> Close Current Instance deve funcionar mesmo para os aplicativos que não permitem a execução de várias cópias simultaneamente, pois neste caso, a nova instância pode receber um argumento de linha de comando que indicará que há uma reboot em andamento Portanto, a verificação de outras instâncias em execução não será necessária. Esperar que a primeira instância realmente termine a minha implementação também é absolutamente imperativo que não haja duas instâncias em execução em paralelo.

Temo que reiniciar o aplicativo inteiro usando o Process está abordando o problema de maneira errada.

Uma maneira mais fácil é modificar o arquivo Program.cs para reiniciar:

  static bool restart = true; // A variable that is accessible from program static int restartCount = 0; // Count the number of restarts static int maxRestarts = 3; // Maximum restarts before quitting the program ///  /// The main entry point for the application. ///  [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); while (restart && restartCount < maxRestarts) { restart = false; // if you like.. the program can set it to true again restartCount++; // mark another restart, // if you want to limit the number of restarts // this is useful if your program is crashing on // startup and cannot close normally as it will avoid // a potential infinite loop try { Application.Run(new YourMainForm()); } catch { // Application has crashed restart = true; } } } 

Eu tive um problema semelhante, mas o meu estava relacionado a memory leaks incontrolável que não consegui encontrar em um aplicativo que precisa ser executado 24 horas por dia, 7 dias por semana. Com o cliente, concordei que o horário seguro para reiniciar o aplicativo era 03:00, se o consumo de memory ultrapassasse o valor definido.

Eu tentei Application.Restart , mas desde que parece usar algum mecanismo que inicia nova instância enquanto ele já está em execução, eu fui para outro esquema. Eu usei o truque que o sistema de arquivos manipula persistir até que o processo que os criou morra. Então, do aplicativo, eu soltei o arquivo no disco e não Dispose() o identificador. Eu usei o arquivo para enviar ‘eu’ executável e iniciar o diretório também (para adicionar flexibilidade).

Código:

 _restartInProgress = true; string dropFilename = Path.Combine(Application.StartupPath, "restart.dat"); StreamWriter sw = new StreamWriter(new FileStream(dropFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)); sw.WriteLine(Application.ExecutablePath); sw.WriteLine(Application.StartupPath); sw.Flush(); Process.Start(new ProcessStartInfo { FileName = Path.Combine(Application.StartupPath, "VideoPhill.Restarter.exe"), WorkingDirectory = Application.StartupPath, Arguments = string.Format("\"{0}\"", dropFilename) }); Close(); 

Close() no final iniciaria o encerramento do aplicativo, e o identificador de arquivo que eu usava para o StreamWriter aqui seria mantido aberto até que o processo realmente morresse. Então…

Restarter.exe entra em ação. Tenta ler o arquivo no modo exclusivo, impedindo que ele obtenha access até que o aplicativo principal não esteja morto, inicie o aplicativo principal, exclua o arquivo e exista. Eu acho que não pode ser mais simples:

 static void Main(string[] args) { string filename = args[0]; DateTime start = DateTime.Now; bool done = false; while ((DateTime.Now - start).TotalSeconds < 30 && !done) { try { StreamReader sr = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)); string[] runData = new string[2]; runData[0] = sr.ReadLine(); runData[1] = sr.ReadLine(); Thread.Sleep(1000); Process.Start(new ProcessStartInfo { FileName = runData[0], WorkingDirectory = runData[1] }); sr.Dispose(); File.Delete(filename); done = true; } catch (Exception ex) { Console.WriteLine(ex.Message); } Thread.Sleep(1000); } } 

Que tal criar um arquivo bat, executar o arquivo em lotes antes de fechar e, em seguida, feche a instância atual.

O arquivo de lote faz isso:

  1. espere em um loop para verificar se o processo foi encerrado.
  2. iniciar o processo.

Eu uso o seguinte e ele faz exatamente o que você está procurando:

 ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment; UpdateCheckInfo info = null; info = ad.CheckForDetailedUpdate(); if (info.IsUpdateRequired) { ad.UpdateAsync(); // I like the update dialog MessageBox.Show("Application was upgraded and will now restart."); Environment.Exit(0); } 

Para usar como logout você precisa encerrar todos os aplicativos do cache de ram, então feche o aplicativo primeiro e execute-o novamente

// ao clicar no botão Logout

 foreach(Form frm in Application.OpenForms.Cast
().ToList()) { frm.Close(); } System.Diagnostics.Process.Start(Application.ExecutablePath);

O problema de usar Application.Restart () é que ele inicia um novo processo, mas o “antigo” ainda permanece. Por isso, decidi Matar o processo antigo usando o seguinte trecho de código:

  if(Condition){ Application.Restart(); Process.GetCurrentProcess().Kill(); } 

E funciona bem de verdade. No meu caso, o MATLAB e um aplicativo C # estão compartilhando o mesmo database SQLite. Se o MATLAB estiver usando o database, o Form-App deverá reiniciar (+ Contagem regressiva) novamente, até que o MATLAB redefina seu bit ocupado no database. (Apenas para informação lateral)