Tworzenie aplikacji WinForm w języku C # .NET 2.0. Potrzebujesz aplikacji do zamknięcia i ponownego uruchomienia.
Application.Restart();
Powyższa metoda okazała się zawodna .
Jaki jest lepszy sposób na ponowne uruchomienie aplikacji?
Tworzenie aplikacji WinForm w języku C # .NET 2.0. Potrzebujesz aplikacji do zamknięcia i ponownego uruchomienia.
Application.Restart();
Powyższa metoda okazała się zawodna .
Jaki jest lepszy sposób na ponowne uruchomienie aplikacji?
Odpowiedzi:
Niestety nie możesz użyć Process.Start () do uruchomienia instancji aktualnie działającego procesu. Zgodnie z dokumentacją Process.Start (): "Jeśli proces już działa, nie jest uruchamiany żaden dodatkowy zasób procesu ..."
Ta technika będzie działać dobrze w debugerze VS (ponieważ VS wykonuje jakąś magię, która powoduje, że Process.Start myśli, że proces nie jest już uruchomiony), ale zakończy się niepowodzeniem, jeśli nie zostanie uruchomiony w debugerze. (Zauważ, że może to być specyficzne dla systemu operacyjnego - wydaje mi się, że pamiętam, że w niektórych moich testach działało na XP lub Vista, ale może po prostu pamiętam uruchamianie go pod debugerem).
Ta technika jest dokładnie tą, której użył ostatni programista w projekcie, nad którym obecnie pracuję, i od jakiegoś czasu próbuję znaleźć obejście tego problemu. Jak dotąd znalazłem tylko jedno rozwiązanie i wydaje mi się po prostu brudne i niezdarne: uruchom drugą aplikację, która czeka w tle na zakończenie pierwszej aplikacji, a następnie ponownie uruchamia pierwszą aplikację. Jestem pewien, że to zadziała, ale fuj.
Edycja: Korzystanie z drugiej aplikacji działa. W drugiej aplikacji zrobiłem tylko:
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, "");
}
(To jest bardzo uproszczony przykład. Prawdziwy kod ma wiele funkcji sprawdzania poprawności, obsługi błędów itp.)
Process.Startnie dotyczy listy uruchomionych procesów systemu operacyjnego. To stwierdzenie dokumentacja mówi tylko o tej instancji obiektu z Processklasy. ProcessKlasa może być dołączony do uruchomionego procesu, ale może być również w stanie przed startem. Moim zdaniem to błąd konstrukcyjny. Najlepszą praktyką, IMO, jest nigdy ponowne używanie Process instancji i natychmiastowe jej uruchomienie po utworzeniu. Najlepiej użyć Process.Startmetody statycznej . Wtedy ta wada dokumentacji i projektu nigdy nie wchodzi w grę.
WaitForExit(1000). Ale całe czekanie nie jest konieczne, aby rozpocząć nowy proces. Może to być dodatkowe zachowanie, które chcesz, ale nie jest wymagane rozpoczęcie nowego procesu.
O wiele prostsze podejście, które się sprawdziło, to:
Application.Restart();
Environment.Exit(0);
Zachowuje to argumenty wiersza polecenia i działa pomimo programów obsługi zdarzeń, które normalnie uniemożliwiają zamknięcie aplikacji.
Wywołanie Restart () próbuje wyjść, mimo to uruchamia nową instancję i wraca. Następnie wywołanie Exit () kończy proces, nie dając żadnej obsłudze zdarzeń szansy na uruchomienie. Jest bardzo krótki okres, w którym działają oba procesy, co nie stanowi problemu w moim przypadku, ale może w innych przypadkach.
Kod zakończenia 0 w Environment.Exit(0);określa czyste zamknięcie. Możesz również wyjść z 1, aby określić, że wystąpił błąd.
OnClose()zdarzeń formularza i podobnych.
Jeśli jesteś w głównej formie aplikacji, spróbuj użyć
System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app
Enviorment.Exit(0)też wykona robotę.
Enviorment.Exitjest brudnym i dość inwazyjnym wyjściem, ponieważ uniemożliwia uruchomienie kodu czyszczącego aplikację. Przez większość czasu nie jest to właściwy wybór.
Mogę się spóźnić na imprezę, ale oto moje proste rozwiązanie i działa jak urok w każdej aplikacji, którą mam:
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
{ }
Miałem dokładnie ten sam problem i ja również miałem wymóg zapobiegania zduplikowanym instancjom - proponuję alternatywne rozwiązanie do tego, które proponuje HiredMind (które będzie działać dobrze).
To, co robię, to uruchamianie nowego procesu z processId starego procesu (tego, który wyzwala restart) jako argumentem wiersza 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);
Następnie po uruchomieniu nowej aplikacji najpierw analizuję argumenty wiersza cm i sprawdzam, czy jest tam flaga restartu z processId, a następnie czekam, aż proces zakończy się:
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
}
}
Oczywiście nie pokazuję wszystkich kontroli bezpieczeństwa, które przeprowadziłem itp.
Nawet jeśli nie jest to idealne rozwiązanie - uważam to za ważną alternatywę, dzięki czemu nie musisz mieć osobnej aplikacji tylko do obsługi ponownego uruchomienia.
/allowMultipleInstancesflagę niż raczej dziwną /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);
Wydaje się, że działa lepiej niż Application.Restart ();
Nie jestem pewien, jak sobie z tym radzi, jeśli program chroni przed wieloma wystąpieniami. Domyślam się, że lepiej byłoby uruchomić drugi plik .exe, który zatrzymuje się, a następnie uruchamia główną aplikację.
To proste, wystarczy wywołać Application.Restart()metody, które mają tendencję do wywoływania aplikacji w celu ponownego uruchomienia. Ale musisz wyjść ze środowiska lokalnego z ich kodami błędów:
Application.Restart();
Environment.exit(int errorcode);
możesz utworzyć wyliczenie kodu błędu, aby móc go efektywnie używać.
Inną metodą jest po prostu wyjście z aplikacji i rozpoczęcie procesu posiadającego ścieżkę do pliku wykonywalnego:
Application.exit();
System.Diagnostics.Process.Start(Application.ExecutablePath);
Wypróbuj ten kod:
bool appNotRestarted = true;
Ten kod musi również znajdować się w funkcji:
if (appNotRestarted == true) {
appNotRestarted = false;
Application.Restart();
Application.ExitThread();
}
Wymyśliłem inne rozwiązanie, być może każdy też może z niego skorzystać.
string batchContent = "/c \"@ECHO OFF & timeout /t 6 > nul & start \"\" \"$[APPPATH]$\" & exit\"";
batchContent = batchContent.Replace("$[APPPATH]$", Application.ExecutablePath);
Process.Start("cmd", batchContent);
Application.Exit();
Kod jest uproszczony, więc zadbaj o wyjątki i takie tam;)
Zapominasz o opcjach / parametrach wiersza polecenia, które zostały przekazane do aktualnie działającej instancji. Jeśli ich nie przekażesz, nie wykonasz prawdziwego restartu. Ustaw parametry Process.StartInfoza pomocą klonu parametrów procesu, a następnie zacznij.
Na przykład, jeśli twój proces został uruchomiony jako myexe -f -nosplash myfile.txt, twoja metoda byłaby wykonywana tylko myexebez tych wszystkich flag i parametrów.
Chciałem, aby nowa aplikacja została uruchomiona po wyłączeniu starej.
Używanie process.WaitForExit () do czekania na zamknięcie własnego procesu nie ma sensu. To zawsze się skończy.
Tak więc moje podejście polega na użyciu Application.Exit (), a następnie czekania, ale zezwalam na przetwarzanie zdarzeń przez pewien czas. Następnie uruchom nową aplikację z tymi samymi argumentami, co poprzednia.
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 );
}
Możesz także użyć Restarter .
Restarter to aplikacja, która automatycznie monitoruje i ponownie uruchamia programy i aplikacje, które uległy awarii lub zawiesiły się. Pierwotnie został opracowany w celu monitorowania i ponownego uruchamiania serwerów gier, ale spełni swoje zadanie dla dowolnej konsoli lub programu lub aplikacji opartej na formularzu
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 zwraca ścieżkę do pliku aplikacji .exe. Postępuj zgodnie z kolejnością wywołań. Możesz chcieć umieścić go w klauzuli try-catch.
Co powiesz na utworzenie pliku bat, uruchomienie pliku wsadowego przed zamknięciem, a następnie zamknięcie bieżącej instancji.
Plik wsadowy robi to:
Oto moje 2 centy:
Sekwencja Uruchom nową instancję-> Zamknij bieżącą instancję powinna działać nawet dla aplikacji, które nie pozwalają na uruchamianie wielu kopii jednocześnie, ponieważ w tym przypadku do nowej instancji może zostać przekazany argument wiersza polecenia, który wskaże, że trwa ponowne uruchamianie więc sprawdzanie innych uruchomionych instancji nie będzie konieczne. Oczekiwanie na zakończenie pierwszej instancji również zostanie zaimplementowane, jeśli jest absolutnie konieczne, aby żadne dwie intencje nie działały równolegle.
Obawiam się, że ponowne uruchomienie całej aplikacji przy użyciu Process to niewłaściwe podejście do Twojego problemu.
Łatwiejszym sposobem jest zmodyfikowanie pliku Program.cs w celu ponownego uruchomienia:
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;
}
}
}
Miałem podobny problem, ale mój był związany z niemożliwym do zarządzania wyciekiem pamięci, którego nie mogłem znaleźć w aplikacji, która musi działać 24/7. Z klientem ustaliłem, że bezpieczny czas ponownego uruchomienia aplikacji to 03:00, jeśli zużycie pamięci przekroczy zdefiniowaną wartość.
Próbowałem Application.Restart, ale ponieważ wydaje się, że używa jakiegoś mechanizmu, który uruchamia nową instancję, gdy jest już uruchomiona, wybrałem inny schemat. Użyłem sztuczki, że system plików utrzymuje się, dopóki proces, który je utworzył, nie umrze. Tak więc z aplikacji upuściłem plik na dysk, ale nie Dispose()poradziłem sobie z tym. Użyłem tego pliku do wysłania `` siebie '' pliku wykonywalnego i katalogu startowego (aby zwiększyć elastyczność).
Kod:
_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()na końcu zainicjowałoby zamknięcie aplikacji, a uchwyt pliku, którego użyłem StreamWritertutaj, byłby otwarty, dopóki proces naprawdę nie umarł. Następnie...
Do akcji wkracza Restarter.exe. PRÓBUJE odczytać plik w trybie wyłączności, uniemożliwiając mu uzyskanie dostępu do czasu śmierci głównej aplikacji, a następnie uruchamia główną aplikację, usuwa plik i istnieje. Myślę, że prościej nie może być:
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);
}
}
Używam następujących i robi dokładnie to, czego szukasz:
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);
}
do używania Jako wylogowania musisz zamknąć wszystkie aplikacje z pamięci RAM, więc zamknij najpierw aplikację, a następnie uruchom ją ponownie
// po kliknięciu przycisku Wyloguj
foreach(Form frm in Application.OpenForms.Cast<Form>().ToList())
{
frm.Close();
}
System.Diagnostics.Process.Start(Application.ExecutablePath);
Problem z użyciem Application.Restart () polega na tym, że uruchamia ona nowy proces, ale „stary” wciąż pozostaje. Dlatego zdecydowałem się zabić stary proces za pomocą następującego fragmentu kodu:
if(Condition){
Application.Restart();
Process.GetCurrentProcess().Kill();
}
I działa dobrze. W moim przypadku MATLAB i aplikacja C # współużytkują tę samą bazę danych SQLite. Jeśli MATLAB korzysta z bazy danych, aplikacja Form powinna ponownie uruchomić się (+ Countdown), aż MATLAB zresetuje swój bit zajętości w bazie danych. (Tylko dla dodatkowych informacji)