Bir C # .NET 2.0 WinForm Uygulaması Geliştirme. Uygulamanın kendini kapatması ve yeniden başlatması gerekiyor.
Application.Restart();
Yukarıdaki yöntemin güvenilmez olduğu kanıtlanmıştır .
Uygulamayı yeniden başlatmanın daha iyi bir yolu nedir?
Bir C # .NET 2.0 WinForm Uygulaması Geliştirme. Uygulamanın kendini kapatması ve yeniden başlatması gerekiyor.
Application.Restart();
Yukarıdaki yöntemin güvenilmez olduğu kanıtlanmıştır .
Uygulamayı yeniden başlatmanın daha iyi bir yolu nedir?
Yanıtlar:
Maalesef şu anda çalışan işlemin bir vakasını başlatmak için Process.Start () kullanamazsınız. Process.Start () belgelerine göre: "İşlem zaten çalışıyorsa, hiçbir ek işlem kaynağı başlatılmaz ..."
Bu teknik, VS hata ayıklayıcı altında iyi çalışır (çünkü VS, Process.Start'ın işlemin zaten çalışmadığını düşünmesine neden olan bir tür sihir yapar), ancak hata ayıklayıcı altında çalıştırılmadığında başarısız olur. (Bunun işletim sistemine özgü olabileceğini unutmayın - bazı testlerimde XP veya Vista'da çalıştığını hatırlıyorum, ancak hata ayıklayıcı altında çalıştırdığımı hatırlıyor olabilirim.)
Bu teknik, şu anda üzerinde çalıştığım projedeki son programcı tarafından tam olarak kullanılan tekniktir ve uzun süredir bunun için bir geçici çözüm bulmaya çalışıyorum. Şimdiye kadar sadece bir çözüm buldum ve bu bana kirli ve rahatsız edici geliyor: ilk uygulamanın sonlandırılması için arka planda bekleyen ikinci bir uygulama başlatın ve ardından 1. uygulamayı yeniden başlatın. Eminim işe yarar, ama iğrenç.
Düzenleme: 2. bir uygulama kullanmak işe yarar. İkinci uygulamada yaptığım tek şey şuydu:
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, "");
}
(Bu çok basitleştirilmiş bir örnektir. Gerçek kodda çok sayıda akıl sağlığı denetimi, hata işleme vb. Vardır)
Process.Startçalışan işletim sistemi işlemlerinin listesine bakmıyor. Bu belgeler deyimi sadece bahsediyor nesne örneği içinde Processsınıfından. ProcessSınıf çalışan bir yönteme bağlı olabilir, ancak aynı zamanda bir Başlatılmadı halde olabilir. Bence bu bir tasarım berbat. En iyi uygulama, IMO, bir Process örneği asla yeniden kullanmamak ve oluşturulduktan hemen sonra başlatmaktır. İdeal olarak statik Process.Startyöntemi kullanın . O zaman bu dokümantasyon ve tasarım hatası asla devreye girmez.
WaitForExit(1000). Ancak yeni bir sürecin başlatılması için tüm bekleme gerekli değildir. İstediğiniz ek davranış olabilir, ancak yeni bir işlem başlatmanız gerekmez.
Benim için işe yarayan çok daha basit bir yaklaşım:
Application.Restart();
Environment.Exit(0);
Bu, komut satırı bağımsız değişkenlerini korur ve normalde uygulamanın kapanmasını engelleyen olay işleyicilerine rağmen çalışır.
Restart () çağrısı çıkmaya çalışır, yine de yeni bir örnek başlatır ve geri döner. Exit () çağrısı daha sonra herhangi bir olay işleyicisine çalışma şansı vermeden işlemi sonlandırır. Her iki sürecin de çalıştığı çok kısa bir dönem var, bu benim durumumda bir sorun değil, belki başka durumlarda olabilir.
Çıkış kodu 0, Environment.Exit(0);temiz bir kapatmayı belirtir. Ayrıca bir hatanın oluştuğunu belirtmek için 1 ile çıkabilirsiniz.
OnClose()olayları ve benzerlerini ortaya çıkarmaz.
Ana uygulama formundaysanız kullanmayı deneyin
System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app
Enviorment.Exit(0)da işi yapacak.
Enviorment.Exitkirli ve oldukça istilacı bir çıkıştır çünkü uygulama temizleme kodunun çalışmasını engeller. Çoğu zaman doğru seçim değil.
Partiye geç kalmış olabilirim ama işte benim basit çözümüm ve sahip olduğum her uygulamada bir cazibe gibi çalışıyor:
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
{ }
Ben de aynı sorunu yaşadım ve yinelenen örnekleri önleme zorunluluğum vardı - HiredMind'ın önerdiği (iyi çalışacak) alternatif bir çözüm öneriyorum.
Yaptığım şey, bir cmd satırı bağımsız değişkeni olarak eski sürecin processId (yeniden başlatmayı tetikleyen) ile yeni süreci başlatmaktır:
// 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);
Sonra yeni uygulama başladığında, önce cm satırı değiştirgelerini ayrıştırıyorum ve yeniden başlatma bayrağının bir processId ile orada olup olmadığını kontrol ediyorum, ardından bu işlemin Çıkmasını bekliyorum:
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
}
}
Açıkçası, sahip olduğum tüm güvenlik kontrollerini vb. Göstermiyorum.
İdeal olmasa bile - bunu geçerli bir alternatif buluyorum, böylece yalnızca yeniden başlatmayı işlemek için ayrı bir uygulamaya sahip olmanız gerekmiyor.
/allowMultipleInstancesGarip /restartolanı yerine bir bayrak 'bulmalarını' tercih ederim .
// 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);
Bu Application.Restart () 'den daha iyi çalışıyor gibi görünüyor;
Programınız birden çok örneğe karşı koruma sağlıyorsa bunun nasıl işleyeceğinden emin değilsiniz. Tahminim, sizin için ana uygulamanızı duraklatan ve ardından başlatan ikinci bir .exe başlatmanız daha iyi olur.
Çok basit, sadece Application.Restart()yeniden başlatılması için uygulamanızı çağırma eğiliminde olan yöntemleri çağırmanız yeterlidir . Ancak yerel ortamdan hata kodlarıyla çıkmanız gerekir:
Application.Restart();
Environment.exit(int errorcode);
verimli bir şekilde kullanabilmeniz için bir hata kodu listesi oluşturabilirsiniz.
Başka bir yöntem de uygulamadan çıkmak ve işlemi yürütülebilir bir yola sahip olarak başlatmaktır:
Application.exit();
System.Diagnostics.Process.Start(Application.ExecutablePath);
Bu kodu deneyin:
bool appNotRestarted = true;
Bu kod ayrıca işlevde olmalıdır:
if (appNotRestarted == true) {
appNotRestarted = false;
Application.Restart();
Application.ExitThread();
}
Başka bir çözüm buldum, belki herkes de kullanabilir.
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 basitleştirilmiştir, bu nedenle İstisnalara ve diğer şeylere dikkat edin;)
Şu anda çalışan örneğinize aktarılan komut satırı seçeneklerini / parametrelerini unutuyorsunuz. Bunları iletmezseniz, gerçek bir yeniden başlatma yapmazsınız. Process.StartInfoİşlem parametrelerinizin bir klonu ile ayarlayın , ardından bir başlayın.
Örneğin, işleminiz olarak başlatıldıysa myexe -f -nosplash myfile.txt, yönteminiz yalnızca myexetüm bu işaretler ve parametreler olmadan çalışır.
Eskisi kapandıktan sonra yeni uygulamanın başlamasını istedim.
Kendi işleminizin kapanmasını beklemek için process.WaitForExit () kullanmak mantıklı değildir. Her zaman zaman aşımına uğrayacaktır.
Bu yüzden benim yaklaşımım Application.Exit () kullanmak ve sonra beklemek, ancak olayların bir süre işlenmesine izin vermektir. Daha sonra eskisiyle aynı argümanlara sahip yeni bir uygulama başlatın.
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 );
}
Restarter'ı da kullanabilirsiniz .
Restarter, çökmüş veya asılı programları ve uygulamaları otomatik olarak izleyen ve yeniden başlatan bir uygulamadır. Başlangıçta oyun sunucularını izlemek ve yeniden başlatmak için geliştirildi, ancak herhangi bir konsol veya form tabanlı program veya uygulama için işi yapacak
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 , aplication .exe dosya yolunuzu döndürür Lütfen çağrıların sırasını izleyin. Bunu bir deneme yan tümcesine yerleştirmek isteyebilirsiniz.
Bir bat dosyası oluşturmaya, kapatmadan önce toplu iş dosyasını çalıştırmaya ve ardından geçerli örneği kapatmaya ne dersiniz?
Toplu iş dosyası şunu yapar:
İşte benim 2 sentim:
Yeni Örneği Başlat-> Geçerli Örneği Kapat dizisi, aynı anda birden fazla kopya çalıştırılmasına izin vermeyen uygulamalar için bile çalışmalıdır, çünkü bu durumda yeni örneğe, devam eden bir yeniden başlatma olduğunu belirten bir komut satırı bağımsız değişkeni geçirilebilir. bu nedenle, çalışan diğer örnekleri kontrol etmek gerekli olmayacaktır. İki özelliğin paralel olarak çalışmaması kesinlikle zorunluysa, ilk örneğin benim de uygulanmamı gerçekten bitirmesini bekliyorum.
Application.Restart () kullanmanın sorunu, yeni bir işlem başlatması, ancak "eski" olanın hala kalmasıdır. Bu nedenle, aşağıdaki kod parçacığını kullanarak eski süreci sonlandırmaya karar verdim:
if(Condition){
Application.Restart();
Process.GetCurrentProcess().Kill();
}
Ve gayet iyi çalışıyor. Benim durumumda MATLAB ve bir C # Uygulaması aynı SQLite veritabanını paylaşıyor. MATLAB veritabanını kullanıyorsa, MATLAB veritabanındaki meşgul bitini sıfırlayana kadar Form Uygulaması yeniden (+ Geri Sayım) yeniden başlatılmalıdır. (Yan bilgi için)
Process'i kullanarak tüm uygulamayı yeniden başlatmanın sorununuza yanlış şekilde yaklaşmasından korkuyorum.
Daha kolay bir yol, yeniden başlatmak için Program.cs dosyasını değiştirmektir:
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;
}
}
}
Benzer bir sorunum vardı, ancak benimki 7/24 çalışması gereken bir uygulamada bulamadığım yönetilemeyen bellek sızıntısı ile ilgiliydi. Müşteriyle, bellek tüketimi tanımlanan değerin üzerindeyse uygulamayı yeniden başlatmak için güvenli zamanın 03:00 olduğunu kabul ettim.
Denedim Application.Restart, ancak zaten çalışırken yeni örneği başlatan bir mekanizma kullanıyor gibi göründüğü için başka bir şemaya gittim. Dosya sisteminin işleyeceği hileyi, onları oluşturan süreç ölene kadar devam ettirdim. Bu yüzden, Uygulamadan dosyayı diske bıraktım veDispose() bıraktım ve işleme koymadım. Dosyayı 'kendim' çalıştırılabilir ve başlangıç dizinini göndermek için kullandım (esneklik eklemek için).
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() sonunda uygulama kapatmayı başlatır ve kullandığım dosya tanıtıcısı StreamWriter burada süreç gerçekten ölünceye kadar açık tutulacak. Sonra...
Restarter.exe devreye girer. Dosyayı özel modda okumaya ÇALIŞIR, ana uygulama ölünceye kadar erişim kazanmasını engeller, ardından ana uygulamayı başlatır, dosyayı siler ve var olur. Sanırım daha basit olamaz:
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);
}
}
Aşağıdakileri kullanıyorum ve tam olarak aradığınız şeyi yapıyor:
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);
}
As oturumu kapatmak için tüm uygulamayı Ram Cache'den sonlandırmanız gerekir, bu nedenle önce Uygulamayı kapatın ve ardından Yeniden Çalıştırın
// Çıkış Düğmesine tıklandığında
foreach(Form frm in Application.OpenForms.Cast<Form>().ToList())
{
frm.Close();
}
System.Diagnostics.Process.Start(Application.ExecutablePath);
Örneğin şunları yapan bir uygulamayı ele alalım:
Başvuru kayıtlı değilken; (başlangıçta) uygulama, kullanıcıdan uygulamayı kaydettirmesini ve bir oturum açma hesabı oluşturmasını istemelidir.
Kayıt gönderildikten ve oturum açma kimlik bilgileri oluşturulduktan sonra; uygulama yeniden başlatılmalı, kaydı kontrol etmeli ve kullanıcının eklenen kimlik bilgileriyle oturum açmasını istemelidir (böylece kullanıcı tüm uygulama özelliklerine erişebilir).
Sorun: Uygulamayı Visual Studio'dan oluşturup başlatarak; Aşağıdaki 4 alternatiften herhangi biri gerekli görevleri yerine getirmede başarısız olacaktır.
/*
* Note(s):
* Take into consideration that the lines bellow don't represent a code block.
* They are just a representation of possibilities,
* that can be used to restart the application.
*/
Application.Restart();
Application.Exit();
Environment.Exit(int errorCode);
Process.GetCurrentProcess().Kill();
Ne olur: Kaydı oluşturduktan, Oturum Açtıktan ve Application.Restart () 'ı çağırdıktan sonra; uygulama (garip bir şekilde) Kayıt Formunu yeniden açar ve bir Veritabanındaki verileri atlar (kaynak "Daha Yeniyse Kopyala" olarak ayarlanmış olsa bile).
Çözüm: Uygulamayı Toplu Oluşturmak (benim için) yukarıdaki satırlardan herhangi birinin beklendiği gibi çalıştığının bir kanıtıydı. Uygulamayı Visual Studio ile oluşturup çalıştırırken değil.
İlk olarak uygulamayı toplu olarak oluşturmayı denerdim; Visual Studio dışında çalıştırın ve Application.Restart () gerçekten beklendiği gibi çalışıp çalışmadığını kontrol edin.
Ayrıca bu konu ile ilgili daha fazla bilgiyi kontrol edin: C # WinForm Uygulamamı nasıl yeniden başlatırım?