Desarrollo de una aplicación WinForm C # .NET 2.0. Necesita que la aplicación se cierre y se reinicie.
Application.Restart();
El método anterior ha demostrado ser poco confiable .
¿Cuál es una mejor forma de reiniciar la aplicación?
Desarrollo de una aplicación WinForm C # .NET 2.0. Necesita que la aplicación se cierre y se reinicie.
Application.Restart();
El método anterior ha demostrado ser poco confiable .
¿Cuál es una mejor forma de reiniciar la aplicación?
Respuestas:
Desafortunadamente, no puede usar Process.Start () para iniciar una instancia del proceso que se está ejecutando actualmente. Según los documentos de Process.Start (): "Si el proceso ya se está ejecutando, no se inicia ningún recurso de proceso adicional ..."
Esta técnica funcionará bien con el depurador VS (porque VS hace algún tipo de magia que hace que Process.Start piense que el proceso aún no se está ejecutando), pero fallará cuando no se ejecute con el depurador. (Tenga en cuenta que esto puede ser específico del sistema operativo; creo recordar que en algunas de mis pruebas, funcionó en XP o Vista, pero es posible que solo recuerde haberlo ejecutado bajo el depurador).
Esta técnica es exactamente la que utilizó el último programador 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 sucia y torpe: inicie una segunda aplicación, que espera en segundo plano a que termine la primera aplicación, luego vuelve a iniciar la primera aplicación. Estoy seguro de que funcionaría, pero qué asco.
Editar: El uso de 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 muchas comprobaciones de cordura, manejo de errores, etc.)
fuente
Process.Start
no mira la lista de procesos del sistema operativo en ejecución. Esta declaración de documentación solo habla de esa instancia de objeto de laProcess
clase. LaProcess
clase se puede adjuntar a un proceso en ejecución, pero también puede estar en un estado no iniciado. En mi opinión, este es un error de diseño. La mejor práctica, en mi opinión, es no reutilizar nunca unaProcess
instancia e iniciarla inmediatamente después de su creación. Idealmente, use elProcess.Start
método estático . Entonces, esta falla de documentación y diseño nunca entrará en juego.WaitForExit(1000)
. Pero no es necesaria toda la espera para iniciar un nuevo proceso. Puede que desee un comportamiento adicional, pero no es necesario para iniciar un nuevo proceso.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 el cierre de la aplicación.
La llamada a Restart () intenta salir, inicia una nueva instancia de todos modos y regresa. La llamada Exit () luego termina el proceso sin dar a ningún controlador de eventos la oportunidad de ejecutarse. Hay un período muy breve en el que ambos procesos se están ejecutando, lo cual no es un problema en mi caso, pero quizás 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 que ocurrió un error.fuente
OnClose()
eventos de formulario y similares.Si está en la forma de la aplicación principal, intente usar
System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application this.Close(); //to turn off current app
fuente
Enviorment.Exit(0)
también hará el trabajo.Enviorment.Exit
es una salida sucia y bastante invasiva porque evita que se ejecute el código de limpieza de la aplicación. No es la elección correcta la mayor parte del tiempo.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 { }
fuente
Tenía exactamente el mismo problema y yo también tenía el requisito de evitar instancias duplicadas: propongo una solución alternativa a la que propone 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 de 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 verifico si el indicador de reinicio está allí con un processId, luego espero a que ese 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, etc.
Incluso si no es ideal, creo que esta es una alternativa válida para que no tenga que tener una aplicación separada solo para manejar el reinicio.
fuente
/allowMultipleInstances
bandera que una bastante extraña/restart
.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 se maneja esto si su programa protege contra múltiples instancias. Supongo que es mejor que inicie un segundo .exe que pausa y luego inicia su aplicación principal por usted.
fuente
Es simple, solo necesita llamar a los
Application.Restart()
métodos que tienden a invocar su aplicación para que se reinicie. Pero debes 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 de manera eficiente.
Otro método es simplemente salir de la aplicación e iniciar el proceso con una ruta ejecutable:
fuente
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(); }
fuente
Descubrí otra solución, tal vez 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 está simplificado, así que ocúpate de las excepciones y demás;)
fuente
Está olvidando las opciones / parámetros de la línea de comandos que se pasaron a su instancia en ejecución. Si no los pasa, no está haciendo un reinicio real. Configure
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 se ejecutaríamyexe
sin todos esos indicadores y parámetros.fuente
Quería que la nueva aplicación se iniciara después de que se apagara la anterior.
Usar process.WaitForSalir () para esperar a que su propio proceso se apague no tiene sentido. Siempre se agotará el tiempo.
Entonces, mi enfoque es usar Application.Salir () y luego esperar, pero permitir que los eventos se procesen, durante 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<string> args = new Queue<string>( 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 ); }
fuente
También puedes usar Restarter .
fuente
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 la ruta del archivo .exe de su aplicación. Siga el orden de las llamadas. Es posible que desee colocarlo en una cláusula try-catch.
fuente
¿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:
fuente
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 varias copias simultáneamente, ya que en este caso la nueva instancia puede recibir un argumento de línea de comando que indicará que hay un reinicio en curso. por lo que no será necesario comprobar si hay otras instancias en ejecución. Esperando a que la primera instancia termine, también se implementará si es absolutamente imperativo que no se ejecuten dos instancias en paralelo.
fuente
Me temo que reiniciar toda la aplicación usando Process está abordando su problema de manera incorrecta.
Una forma más sencilla 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 /// <summary> /// The main entry point for the application. /// </summary> [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; } } }
fuente
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 debe ejecutarse 24 horas al día, 7 días a la semana. Con el cliente, acordé que el momento seguro para reiniciar la aplicación era a las 03:00 a. M. Si el consumo de memoria estaba por encima del valor definido.
Lo intenté
Application.Restart
, pero como parece usar algún mecanismo que inicia una nueva instancia mientras ya se está ejecutando, fui por otro esquema. Utilicé el truco de que los manejos del sistema de archivos persisten hasta que el proceso que los creó muere. Entonces, desde La aplicación, coloqué el archivo en el disco y noDispose()
manejé. Usé el archivo para enviar el ejecutable "yo mismo" 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 identificador de archivo que usé paraStreamWriter
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 obtenga 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 sencillo:
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); } }
fuente
Utilizo 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); }
fuente
para usar As logout, debe terminar todas las aplicaciones de Ram Cache, así que primero cierre la aplicación y luego vuelva a ejecutarla
// al hacer clic en el botón Cerrar sesión
foreach(Form frm in Application.OpenForms.Cast<Form>().ToList()) { frm.Close(); } System.Diagnostics.Process.Start(Application.ExecutablePath);
fuente
El problema de usar Application.Restart () es que inicia un nuevo proceso pero el "antiguo" aún permanece. Por lo tanto, decidí matar el proceso anterior utilizando 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á usando la base de datos, la aplicación de formulario debería reiniciarse (+ Countdown) nuevamente, hasta que MATLAB restablezca su bit de ocupado en la base de datos. (Solo para información al margen)
fuente
Puede incluir su código dentro de una función y cuando sea necesario reiniciar, puede simplemente llamar a la función.
fuente