如何重新启动我的C#WinForm应用程序?

开发一个C#.NET 2.0 WinForm应用程序。 需要应用程序closures并重新启动。

Application.Restart(); 

上述方法已被certificate是不可靠的 。

什么是重新启动应用程序的更好方法?

不幸的是,您不能使用Process.Start()来启动当前正在运行的进程的一个实例。 根据Process.Start()文档:“如果进程已经运行,没有额外的进程资源启动…”

这个技术在VSdebugging器下工作的很好(因为VS有一些神奇的function,导致Process.Start认为这个进程还没有运行),但是当不在debugging器下运行时会失败。 (请注意,这可能是操作系统特定的 – 我似乎记得,在我的一些testing中,它可以在XP或Vista上运行,但我可能只是记得在debugging器下运行它。)

这种技术正是我目前正在使用的项目中的最后一名程序员使用的技术,我一直在试图find一个相当长的解决方法。 到目前为止,我只find了一个解决scheme,对我来说只是感觉肮脏和不便:启动第二个应用程序,在后台等待第一个应用程序终止,然后重新启动第一个应用程序。 我相信它会起作用,但是,哎呀。

编辑:使用第二个应用程序的作品。 我所做的第二个应用程序是:

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

(这是一个非常简单的例子,真正的代码有很多的理智检查,error handling等)

如果你在主要的应用程序forms尝试使用

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

对我来说更简单的方法是:

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

这保留了命令行参数,尽pipe事件处理程序通常会阻止应用程序closures。

Restart()调用尝试退出,无论如何启动一个新的实例并返回。 Exit()调用然后终止进程而不给任何事件处理器一个运行的机会。 有一个非常短暂的时期,两个进程都在运行,这对我来说不是一个问题,但也许在其他情况下。

Environment.Exit(0);退出代码0 Environment.Exit(0); 指定一个干净的closures。 您也可以用1退出以指定发生的错误。

我可能会晚到晚会,但这里是我简单的解决scheme,它像我拥有的​​每一个应用程序的魅力:

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

我有同样的确切问题,我也有要求,以防止重复的情况下 – 我build议一个HiredMind提出的替代解决scheme(这将工作正常)。

我正在做的是用旧进程(触发重启的进程)的processId作为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); 

然后,当新的应用程序启动时,我首先parsing厘米线参数,并检查重新启动标志是否存在processId,然后等待该进程退出:

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

我显然没有显示我所有的安全检查等等。

即使不理想 – 我发现这是一个有效的select,所以你不必有一个单独的应用程序来处理重新启动。

它的简单,你只需要调用Application.Restart()方法,往往会调用你的应用程序被重新启动。 但是您必须从错误代码中退出本地环境:

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

您可以创build一个错误代码枚举,以便您可以使用它。
另一种方法是从应用程序退出并启动具有可执行文件path的进程:

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

开始/退出方法

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

这似乎比Application.Restart();

不知道如果您的程序防止多个实例如何处理。 我的猜测是你会更好地启动第二个.exe暂停,然后启动您的主要应用程序。

试试这个代码:

 bool appNotRestarted = true; 

这个代码也必须在函数中:

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

我想出了另一个解决scheme,也许任何人都可以使用它。

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

代码被简化,所以照顾例外和东西;)

您忘记了传入您当前正在运行的实例的命令行选项/参数。 如果你不通过这些,你并没有真正的重启。 设置Process.StartInfo克隆你的进程的参数,然后做一个开始。

例如,如果您的进程是以myexe -f -nosplash myfile.txt启动的, myexe -f -nosplash myfile.txt您的方法将只执行没有所有这些标志和参数的myexe

我想在旧的应用程序closures后启动新的应用程序。

使用process.WaitForExit()等待你自己的进程closures是没有意义的。 它将永远超时。

所以,我的方法是使用Application.Exit()然后等待,但是允许事件被处理一段时间。 然后用与旧的相同的参数开始一个新的应用程序。

 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 ); } 
 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返回您的应用程序.exe文件path请按照调用的顺序。 你可能想把它放在一个try-catch子句中。

这是我的2美分:

即使对于不允许同时运行多个副本的应用程序,“启动新实例” – >“closures当前实例”序列也可以工作,因为在这种情况下,新实例可能会传递一个命令行参数,这将指示正在重新启动所以检查其他实例运行将不是必要的。 如果没有两个物质并行运行是绝对必要的,那么等待第一个实际上也可以完成我的实施。

你也可以使用Restarter 。

Restarter是一个应用程序,自动监视和重新启动崩溃或挂起的程序和应用程序。 它最初是为监视和重新启动游戏服务器而开发的,但是它可以为任何控制台或基于表单的程序或应用程序提供帮助

我有一个类似的问题,但我的是难以pipe理的内存泄漏,我无法find一个应用程序,必须全天候运行。 与客户,我同意如果内存消耗超过定义的值,安全的时间来重新启动应用程序是凌晨3:00。

我尝试了Application.Restart ,但由于它似乎使用一些机制,开始新的实例,而它已经在运行,我去了另一种scheme。 我使用了文件系统句柄持续的技巧,直到创build它们的进程死亡。 所以,从应用程序,我把文件放到磁盘上,并没有Dispose()处理。 我使用该文件来发送“我自己”的可执行文件和启动目录(以增加灵活性)。

码:

 _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()在最后会启动应用程序closures,我在这里用于StreamWriter文件句柄将保持打开,直到进程真正死亡。 然后…

Restarter.exe进入行动。 它尝试以独占模式读取文件,阻止它获得访问,直到主应用程序没有死,然后启动主应用程序,删除文件并存在。 我想这不能简单一点:

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

如何创build一个bat文件,在closures之前运行该batch file,然后closures当前实例。

batch file执行此操作:

  1. 等待一个循环来检查进程是否退出。
  2. 开始这个过程。

我担心使用Process重新启动整个应用程序会以错误的方式来处理您的问题。

更简单的方法是修改Program.cs文件重新启动:

  static bool restart = true; // A variable that is accessible from program /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); while (restart) { restart = false; // if you like.. the program can set it to true again try { Application.Run(new YourMainForm()); } catch { // Application has crashed restart = true; } } } 

我使用以下,它确实是你在找什么:

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

对于使用注销,你需要终止所有的应用程序从RAMcaching,所以closures应用程序,然后重新运行它

//单击注销button

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

使用Application.Restart()的问题是,它启动一个新的进程,但“老”仍然存在。 因此,我决定通过使用下面的代码片段杀死旧的进程:

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

它的作品适当的好。 在我的情况下,MATLAB和一个C#应用程序共享相同的SQLite数据库。 如果MATLAB正在使用数据库,Form-App应该重新启动(+ Countdown),直到MATLAB重新设置数据库中的忙位。 (仅供参考)