¿Cómo reinicio mi aplicación C # WinForm?

Desarrollando una aplicación WinForm de C # .NET 2.0. Necesita la aplicación para cerrar y reiniciarse.

Application.Restart(); 

El método anterior ha demostrado ser poco confiable .

¿Cuál es una mejor forma de reiniciar la aplicación?

Lamentablemente, no puede usar Process.Start () para iniciar una instancia del proceso en ejecución. De acuerdo con los documentos Process.Start (): “Si el proceso ya se está ejecutando, no se inicia ningún recurso de proceso adicional …”

Esta técnica funcionará bien en el depurador VS (porque VS hace algún tipo de magia que hace que Process.Start piense que el proceso ya no se está ejecutando), pero fallará cuando no se ejecute bajo el depurador. (Tenga en cuenta que esto puede ser específico para el sistema operativo: me parece recordar que en algunas de mis pruebas, funcionó en XP o Vista, pero es posible que solo recuerde ejecutarlo bajo el depurador).

Esta técnica es exactamente la utilizada por el último progtwigdor en el proyecto en el que estoy trabajando actualmente, y he estado tratando de encontrar una solución para esto durante bastante tiempo. Hasta ahora, solo he encontrado una solución y me parece sucio y confuso: iniciar una segunda aplicación, que espera en segundo plano para que la primera aplicación finalice, luego vuelve a lanzar la primera aplicación. Estoy seguro de que funcionaría, pero, puaj.

Editar: Usar una segunda aplicación funciona. Todo lo que hice en la segunda aplicación fue:

  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 es un ejemplo muy simplificado. El código real tiene mucha comprobación de cordura, manejo de errores, etc.)

Si estás en la aplicación principal, intenta usar

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

Un enfoque mucho más simple que funcionó para mí es:

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

Esto conserva los argumentos de la línea de comandos y funciona a pesar de los controladores de eventos que normalmente evitarían que se cierre la aplicación.

La llamada a Restart () intenta salir, inicia una nueva instancia de todos modos y regresa. La llamada a Exit () finaliza el proceso sin dar a los controladores de eventos la oportunidad de ejecutar. Hay un período muy breve en el que se están ejecutando ambos procesos, que no es un problema en mi caso, pero tal vez en otros casos.

El código de salida 0 en Environment.Exit(0); especifica un apagado limpio. También puede salir con 1 para especificar un error.

Puede que llegue tarde a la fiesta, pero esta es mi solución simple y funciona como un encanto con cada aplicación que tengo:

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

Tenía el mismo problema exacto y también tenía un requisito para evitar instancias duplicadas: propongo una solución alternativa a la propuesta por HiredMind (que funcionará bien).

Lo que estoy haciendo es comenzar el nuevo proceso con el processId del proceso anterior (el que desencadena el reinicio) como un argumento de línea 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); 

Luego, cuando se inicia la nueva aplicación, primero analizo los argumentos de la línea cm y compruebo si el indicador de reinicio está allí con un ID de proceso, luego espero que el proceso salga:

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

Obviamente, no estoy mostrando todos los controles de seguridad que tengo instalados, etc.

Incluso si no es lo ideal, considero que esta es una alternativa válida para que no tenga que tener una aplicación separada solo para manejar el reinicio.

Es simple, solo necesita llamar a los métodos Application.Restart() que tienden a invocar su aplicación para que se reinicie. Pero debe tener que salir del entorno Local con sus códigos de error:

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

puede crear una enumeración de código de error para que pueda usarlo efficeintly.
Otro método es simplemente salir de la aplicación e iniciar el proceso con una ruta ejecutable:

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

Método de inicio / salida

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

Esto parece funcionar mejor que Application.Restart ();

No estoy seguro de cómo maneja esto si su progtwig protege contra múltiples instancias. Supongo que sería mejor lanzar un segundo .exe que hace una pausa y luego inicia su aplicación principal por usted.

Prueba este código:

 bool appNotRestarted = true; 

Este código también debe estar en la función:

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

Pensé en otra solución, quizás cualquiera pueda usarla también.

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

El código se simplifica, así que cuídese de las Excepciones y demás;

Se está olvidando las opciones / parámetros de línea de comandos que se pasaron a su instancia actualmente en ejecución. Si no los ingresa, no está haciendo un reinicio real. Establezca el Process.StartInfo con un clon de los parámetros de su proceso, luego comience.

Por ejemplo, si su proceso se inició como myexe -f -nosplash myfile.txt , su método solo ejecutaría myexe sin todos esos indicadores y parámetros.

Quería que la nueva aplicación se iniciara después de que la anterior se apagara.

Usar process.WaitForExit () para esperar a que se cierre el proceso no tiene sentido. Siempre se desconectará.

Entonces, mi enfoque es usar Application.Exit () luego espere, pero permita que los eventos sean procesados, por un período de tiempo. Luego, inicie una nueva aplicación con los mismos argumentos que la anterior.

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

También puedes usar Restarter .

Restarter es una aplicación que automáticamente monitorea y reinicia progtwigs y aplicaciones bloqueados o bloqueados. Originalmente fue desarrollado para monitorear y reiniciar servidores de juego, pero hará el trabajo para cualquier consola o progtwig basado en formularios o aplicación

 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 devuelve su ruta de archivo .exe de aplicación. Siga el orden de las llamadas. Es posible que desee colocarlo en una cláusula try-catch.

Aquí están mis 2 centavos:

La secuencia Iniciar nueva instancia-> Cerrar instancia actual debería funcionar incluso para las aplicaciones que no permiten ejecutar múltiples copias simultáneamente, ya que en este caso la nueva instancia puede pasar un argumento de línea de comando que indicará que hay un reinicio en progreso. por lo que no será necesario verificar si hay otras instancias ejecutándose. Esperar a que la primera instancia termine realmente se implementará también si es absolutamente imprescindible que no se ejecuten dos intstances en paralelo.

Me temo que reiniciar toda la aplicación usando Process es abordar su problema de la manera incorrecta.

Una forma más fácil es modificar el archivo 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; } } } 

Tuve un problema similar, pero el mío estaba relacionado con una pérdida de memoria inmanejable que no pude encontrar en una aplicación que tiene que funcionar 24/7. Con el cliente acordé que el tiempo seguro para reiniciar la aplicación era a las 03:00 AM si el consumo de memoria superaba el valor definido.

Intenté Application.Restart , pero como parece que utiliza algún mecanismo que inicia una nueva instancia mientras ya se está ejecutando, busqué otro esquema. Usé el truco que los manejos del sistema de archivos persisten hasta que muere el proceso que los creó. Entonces, desde la aplicación, dejé caer el archivo en el disco y no Dispose() el identificador. Usé el archivo para enviar el ejecutable ‘myself’ y el directorio de inicio también (para agregar flexibilidad).

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() al final iniciaría el cierre de la aplicación, y el manejador de archivo que utilicé para StreamWriter aquí se mantendría abierto hasta que el proceso realmente muera. Entonces…

Restarter.exe entra en acción. Intenta leer el archivo en modo exclusivo, evitando que tenga acceso hasta que la aplicación principal no esté muerta, luego inicia la aplicación principal, elimina el archivo y existe. Supongo que no puede ser más simple:

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

¿Qué tal crear un archivo bat, ejecutar el archivo por lotes antes de cerrar y luego cerrar la instancia actual.

El archivo por lotes hace esto:

  1. espere en un bucle para verificar si el proceso ha finalizado.
  2. comienza el proceso

Uso lo siguiente y hace exactamente lo que estás buscando:

 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 el cierre de sesión de As, debe finalizar todas las aplicaciones desde Ram Cache, así que cierre la aplicación primero y luego vuelva a ejecutarla.

// al hacer clic en el botón Cerrar sesión

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

El problema de usar Application.Restart () es que comienza un nuevo proceso, pero el “viejo” aún permanece. Por lo tanto, decidí matar el proceso anterior mediante el siguiente fragmento de código:

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

Y funciona bien. En mi caso, MATLAB y una aplicación C # comparten la misma base de datos SQLite. Si MATLAB está utilizando la base de datos, la aplicación de formulario debe reiniciarse (+ cuenta regresiva) nuevamente, hasta que MATLAB restablezca su bit ocupado en la base de datos. (Solo para información adicional)