Entwickeln einer C # .NET 2.0 WinForm-Anwendung. Die Anwendung muss geschlossen und neu gestartet werden.
Application.Restart();
Das obige Verfahren hat sich als unzuverlässig erwiesen .
Was ist ein besserer Weg, um die Anwendung neu zu starten?
Entwickeln einer C # .NET 2.0 WinForm-Anwendung. Die Anwendung muss geschlossen und neu gestartet werden.
Application.Restart();
Das obige Verfahren hat sich als unzuverlässig erwiesen .
Was ist ein besserer Weg, um die Anwendung neu zu starten?
Antworten:
Leider können Sie Process.Start () nicht verwenden, um eine Instanz des aktuell ausgeführten Prozesses zu starten. In den Process.Start () -Dokumenten heißt es: "Wenn der Prozess bereits ausgeführt wird, wird keine zusätzliche Prozessressource gestartet ..."
Diese Technik funktioniert unter dem VS-Debugger einwandfrei (da VS eine Art Magie ausführt, die Process.Start zu der Annahme veranlasst, dass der Prozess noch nicht ausgeführt wird), schlägt jedoch fehl, wenn er nicht unter dem Debugger ausgeführt wird. (Beachten Sie, dass dies möglicherweise betriebssystemspezifisch ist. Ich erinnere mich anscheinend, dass es bei einigen meiner Tests entweder unter XP oder Vista funktioniert hat, aber ich erinnere mich möglicherweise nur daran, es unter dem Debugger ausgeführt zu haben.)
Diese Technik ist genau die, die der letzte Programmierer in dem Projekt verwendet, an dem ich gerade arbeite, und ich habe seit einiger Zeit versucht, eine Problemumgehung dafür zu finden. Bisher habe ich nur eine Lösung gefunden, und es fühlt sich für mich nur schmutzig und klobig an: Starten Sie eine zweite Anwendung, die im Hintergrund darauf wartet, dass die erste Anwendung beendet wird, und startet dann die erste Anwendung neu. Ich bin sicher, es würde funktionieren, aber igitt.
Bearbeiten: Die Verwendung einer zweiten Anwendung funktioniert. Alles was ich in der zweiten App gemacht habe war:
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, "");
}
(Dies ist ein sehr vereinfachtes Beispiel. Der echte Code enthält viele Informationen zur Überprüfung der geistigen Gesundheit, zur Fehlerbehandlung usw.)
Process.StartDie Liste der ausgeführten Betriebssystemprozesse wird nicht angezeigt. Diese Dokumentationsanweisung bezieht sich nur auf diese Objektinstanz der ProcessKlasse. Die ProcessKlasse kann an einen laufenden Prozess angehängt werden, sie kann sich jedoch auch in einem nicht gestarteten Zustand befinden. Meiner Meinung nach ist dies ein Designfehler. Die beste Vorgehensweise, IMO, besteht darin, eine Process Instanz niemals wiederzuverwenden und sofort nach der Erstellung zu starten. Verwenden Sie im Idealfall die statische Process.StartMethode. Dann kommt dieser Dokumentations- und Konstruktionsfehler nie ins Spiel.
WaitForExit(1000). Das gesamte Warten ist jedoch nicht erforderlich, um einen neuen Prozess zu starten. Möglicherweise möchten Sie zusätzliches Verhalten, aber es ist nicht erforderlich, einen neuen Prozess zu starten.
Ein viel einfacherer Ansatz, der für mich funktioniert hat, ist:
Application.Restart();
Environment.Exit(0);
Dies behält die Befehlszeilenargumente bei und funktioniert trotz Ereignishandlern, die normalerweise das Schließen der Anwendung verhindern würden.
Der Restart () -Aufruf versucht zu beenden, startet trotzdem eine neue Instanz und kehrt zurück. Der Aufruf von Exit () beendet dann den Prozess, ohne dass Ereignishandler die Möglichkeit haben, ausgeführt zu werden. Es gibt einen sehr kurzen Zeitraum, in dem beide Prozesse ausgeführt werden, was in meinem Fall kein Problem darstellt, aber möglicherweise in anderen Fällen.
Der Exit-Code 0 in Environment.Exit(0);gibt ein sauberes Herunterfahren an. Sie können auch mit 1 beenden, um anzugeben, dass ein Fehler aufgetreten ist.
Wenn Sie sich in der Haupt-App-Form befinden, versuchen Sie es
System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app
Enviorment.Exit(0)wird auch den Job machen.
Enviorment.Exitist ein schmutziger und ziemlich invasiver Exit, da er verhindert, dass Anwendungsbereinigungscode ausgeführt wird. Meistens nicht die richtige Wahl.
Ich komme vielleicht zu spät zur Party, aber hier ist meine einfache Lösung, die bei jeder Anwendung, die ich habe, wie ein Zauber wirkt:
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
{ }
Ich hatte genau das gleiche Problem und musste auch doppelte Instanzen verhindern - ich schlage eine alternative Lösung zu der von HiredMind vorgeschlagenen vor (die gut funktionieren wird).
Ich starte den neuen Prozess mit der processId des alten Prozesses (der den Neustart auslöst) als cmd-Zeilenargument:
// 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);
Wenn die neue App gestartet wird, analysiere ich zuerst die cm-Zeilenargumente und überprüfe, ob das Neustart-Flag mit einer processId vorhanden ist. Warten Sie dann, bis dieser Prozess beendet ist:
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
}
}
Ich zeige offensichtlich nicht alle Sicherheitsüberprüfungen, die ich durchgeführt habe usw.
Auch wenn dies nicht ideal ist - ich finde, dass dies eine gültige Alternative ist, sodass Sie keine separate App benötigen, um den Neustart durchzuführen.
/allowMultipleInstancesFlagge "finden" als die ziemlich seltsame /restart.
// 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);
Dies scheint besser zu funktionieren als Application.Restart ();
Sie sind sich nicht sicher, wie dies funktioniert, wenn Ihr Programm vor mehreren Instanzen schützt. Ich vermute, Sie sollten besser eine zweite EXE-Datei starten, die pausiert und dann Ihre Hauptanwendung für Sie startet.
Es ist einfach, Sie müssen nur die Application.Restart()Methoden aufrufen , die dazu neigen, Ihre Anwendung zum Neustart aufzurufen. Sie müssen jedoch die lokale Umgebung mit ihren Fehlercodes verlassen:
Application.Restart();
Environment.exit(int errorcode);
Sie können eine Aufzählung von Fehlercodes erstellen, damit Sie diese effektiv verwenden können.
Eine andere Methode besteht darin, die Anwendung zu beenden und den Prozess mit dem ausführbaren Pfad zu starten:
Application.exit();
System.Diagnostics.Process.Start(Application.ExecutablePath);
Versuchen Sie diesen Code:
bool appNotRestarted = true;
Dieser Code muss auch in der Funktion enthalten sein:
if (appNotRestarted == true) {
appNotRestarted = false;
Application.Restart();
Application.ExitThread();
}
Ich habe eine andere Lösung gefunden, vielleicht kann sie auch jeder verwenden.
string batchContent = "/c \"@ECHO OFF & timeout /t 6 > nul & start \"\" \"$[APPPATH]$\" & exit\"";
batchContent = batchContent.Replace("$[APPPATH]$", Application.ExecutablePath);
Process.Start("cmd", batchContent);
Application.Exit();
Code ist vereinfacht, also kümmere dich um Ausnahmen und so;)
Sie vergessen die Befehlszeilenoptionen / -parameter, die an Ihre aktuell ausgeführte Instanz übergeben wurden. Wenn Sie diese nicht übergeben, führen Sie keinen echten Neustart durch. Stellen Sie die Process.StartInfomit einem Klon der Prozessparameter ein und starten Sie dann.
Wenn Ihr Prozess beispielsweise als gestartet wurde myexe -f -nosplash myfile.txt, wird Ihre Methode nur myexeohne all diese Flags und Parameter ausgeführt.
Ich wollte, dass die neue Anwendung gestartet wird, nachdem die alte heruntergefahren wurde.
Die Verwendung von process.WaitForExit () zum Warten auf das Herunterfahren Ihres eigenen Prozesses macht keinen Sinn. Es wird immer eine Auszeit geben.
Mein Ansatz ist es also, Application.Exit () zu verwenden und dann zu warten, aber die Verarbeitung von Ereignissen für einen bestimmten Zeitraum zuzulassen. Starten Sie dann eine neue Anwendung mit denselben Argumenten wie die alte.
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 );
}
Sie können auch Restarter verwenden .
Restarter ist eine Anwendung, die abgestürzte oder blockierte Programme und Anwendungen automatisch überwacht und neu startet. Es wurde ursprünglich zum Überwachen und Neustarten von Spieleservern entwickelt, erledigt jedoch alle Aufgaben für jedes konsolen- oder formularbasierte Programm oder jede Anwendung
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 gibt Ihren .exe-Dateipfad für Anwendungen zurück. Befolgen Sie die Reihenfolge der Aufrufe. Möglicherweise möchten Sie es in eine try-catch-Klausel einfügen.
Wie wäre es, wenn Sie eine Bat-Datei erstellen, die Batch-Datei vor dem Schließen ausführen und dann die aktuelle Instanz schließen.
Die Batch-Datei führt Folgendes aus:
Hier sind meine 2 Cent:
Die Sequenz Neue Instanz starten-> Aktuelle Instanz schließen sollte auch für Anwendungen funktionieren, bei denen nicht mehrere Kopien gleichzeitig ausgeführt werden können. In diesem Fall wird der neuen Instanz möglicherweise ein Befehlszeilenargument übergeben, das angibt, dass ein Neustart ausgeführt wird Daher ist es nicht erforderlich, nach anderen laufenden Instanzen zu suchen. Warten Sie, bis die erste Instanz tatsächlich abgeschlossen ist, und implementieren Sie sie, wenn es unbedingt erforderlich ist, dass keine zwei Instanzen parallel ausgeführt werden.
Ich befürchte, dass ein Neustart der gesamten Anwendung mit Process Ihr Problem falsch angeht.
Eine einfachere Möglichkeit besteht darin, die Datei Program.cs so zu ändern, dass sie neu gestartet wird:
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;
}
}
}
Ich hatte ein ähnliches Problem, aber mein Problem hing mit einem nicht verwaltbaren Speicherverlust zusammen, den ich in einer App, die rund um die Uhr ausgeführt werden muss, nicht finden konnte. Mit dem Kunden stimmte ich zu, dass die sichere Zeit für den Neustart der App 03:00 Uhr war, wenn der Speicherverbrauch über dem definierten Wert lag.
Ich habe es versucht Application.Restart, aber da es einen Mechanismus zu verwenden scheint, der eine neue Instanz startet, während sie bereits ausgeführt wird, habe ich mich für ein anderes Schema entschieden. Ich habe den Trick verwendet, den Dateisystem-Handles beibehalten, bis der Prozess, der sie erstellt hat, stirbt. Also habe ich aus der Anwendung die Datei auf die Festplatte gelegt und nichtDispose() das Handle nicht ausgeführt. Ich habe die Datei verwendet, um die ausführbare Datei und das Startverzeichnis von "mir" zu senden (um die Flexibilität zu erhöhen).
Code:
_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()Am Ende würde das Herunterfahren der App eingeleitet, und das StreamWriterhier verwendete Dateihandle würde offen gehalten, bis der Prozess wirklich stirbt. Dann...
Restarter.exe wird aktiv. Es wird versucht, die Datei im exklusiven Modus zu lesen, um zu verhindern, dass sie Zugriff erhält, bis die Haupt-App nicht tot ist. Anschließend wird die Haupt-App gestartet, die Datei gelöscht und existiert. Einfacher geht es wohl nicht:
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);
}
}
Ich benutze das Folgende und es macht genau das, wonach Sie suchen:
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);
}
Für die Verwendung als Abmeldung müssen Sie alle Apps aus dem Ram-Cache beenden. Schließen Sie daher zuerst die Anwendung und führen Sie sie erneut aus
// beim Klicken auf die Schaltfläche Abmelden
foreach(Form frm in Application.OpenForms.Cast<Form>().ToList())
{
frm.Close();
}
System.Diagnostics.Process.Start(Application.ExecutablePath);
Das Problem bei der Verwendung von Application.Restart () besteht darin, dass ein neuer Prozess gestartet wird, der "alte" jedoch noch vorhanden ist. Aus diesem Grund habe ich beschlossen, den alten Prozess mit dem folgenden Codeausschnitt zu beenden:
if(Condition){
Application.Restart();
Process.GetCurrentProcess().Kill();
}
Und es funktioniert richtig gut. In meinem Fall verwenden MATLAB und eine C # -Anwendung dieselbe SQLite-Datenbank. Wenn MATLAB die Datenbank verwendet, sollte die Form-App erneut gestartet werden (+ Countdown), bis MATLAB sein Besetztbit in der Datenbank zurückgesetzt hat. (Nur zur Information)