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

时间:2009-04-22 21:52:20

标签: c# .net

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

Application.Restart();

上述方法有proven to be unreliable

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

22 个答案:

答案 0 :(得分:52)

如果您使用主应用程序表单,请尝试使用

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

答案 1 :(得分:42)

对我有用的一个更简单的方法是:

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

这保留了命令行参数,并且尽管事件处理程序通常会阻止应用程序关闭。

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

Environment.Exit(0);中的退出代码0指定了干净关闭。您也可以使用1退出以指定发生的错误。

答案 2 :(得分:38)

不幸的是,您无法使用Process.Start()来启动当前正在运行的进程的实例。根据Process.Start()文档: “如果该进程已在运行,则不会启动其他进程资源......”

这种技术在VS调试器下可以正常工作(因为VS会使某些魔法导致Process.Start认为该进程尚未运行),但是在未在调试器下运行时会失败。 (请注意,这可能是特定于操作系统的 - 我似乎记得在我的一些测试中,它适用于XP或Vista,但我可能只记得在调试器下运行它。)

这项技术正是上一个程序员在我正在使用的项目中所使用的技术,我一直试图找到一个解决方法。到目前为止,我只找到了一个解决方案,它只是让我感到肮脏和愚蠢:启动第二个应用程序,在后台等待第一个应用程序终止,然后重新启动第一个应用程序。我相信它会起作用,但是,哎呀。

编辑:使用第二个应用程序。我在第二个应用程序中所做的就是:

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

(这是一个非常简单的例子。真正的代码有很多健全性检查,错误处理等)

答案 3 :(得分:16)

我可能会迟到,但这是我的简单解决方案,它就像我的每个应用程序的魅力一样:

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

答案 4 :(得分:11)

我遇到了同样的问题而且我也要求防止重复的实例 - 我建议HiredMind建议的替代解决方案(这将很好)。

我正在做的是使用旧进程的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);

然后当新应用程序启动时,我首先解析cm行args并检查是否有一个带有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
   }
}

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

即使不理想 - 我发现这是一个有效的替代方案,因此您不必为了处理重启而拥有一个单独的应用程序。

答案 5 :(得分:6)

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

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

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

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

答案 6 :(得分:5)

开始/退出方法

// 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暂停,然后为你启动主应用程序。

答案 7 :(得分:3)

试试这段代码:

bool appNotRestarted = true;

此代码也必须在函数中:

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

答案 8 :(得分:3)

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

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

简化了代码,因此请注意例外和内容;)

答案 9 :(得分:2)

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

例如,如果您的流程以myexe -f -nosplash myfile.txt启动,那么您的方法只会在没有所有这些标记和参数的情况下执行myexe

答案 10 :(得分:2)

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文件路径 请按照通话顺序。您可能希望将其放在try-catch子句中。

答案 11 :(得分:2)

您也可以使用Restarter

  

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

答案 12 :(得分:2)

我希望新应用程序在旧应用程序关闭后启动。

使用process.WaitForExit()等待自己的进程关闭是没有意义的。它总会超时。

所以,我的方法是使用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 );
}

答案 13 :(得分:1)

这是我的2美分:

序列开始新实例 - >关闭当前实例应该适用于不允许同时运行多个副本的应用程序,因为在这种情况下新实例可能会传递一个命令行参数,这将指示存在正在重新启动,因此无需检查其他正在运行的实例。等待第一个实例真正完成我的实施,如果绝对必要的是没有两个实体并行运行。

答案 14 :(得分:1)

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

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

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

答案 15 :(得分:0)

我使用以下内容,它完全符合您的要求:

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

答案 16 :(得分:0)

使用As logout,您需要终止Ram Cache中的所有应用程序 首先关闭应用程序,然后重新运行

//点击退出按钮

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

答案 17 :(得分:0)

如何创建bat文件,在关闭之前运行批处理文件,然后关闭当前实例。

批处理文件执行此操作:

  1. 在循环中等待检查​​进程是否已退出。
  2. 开始这个过程。

答案 18 :(得分:0)

我有一个类似的问题,但我的是与无法管理的内存泄漏有关,我无法在一个必须全天候运行的应用程序上找到。对于客户,我同意如果内存消耗超过定义值,则重启应用程序的安全时间是03:00 AM。

我尝试Application.Restart,但由于它似乎使用某种机制在它已经运行时启动新实例,我去了另一个方案。我使用了文件系统处理的技巧,直到创建它们的进程死掉。因此,从应用程序中,我将文件删除到磁盘,并没有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()将启动应用程序关闭,我在此处用于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);
    }
}

答案 19 :(得分:0)

使用 Application.Restart()的问题是,它启动了一个新进程,但仍然保留了“旧”进程。因此,我决定使用以下代码片段来杀死旧进程:

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

它的效果很好。在我的例子中,MATLAB和C#Application共享相同的SQLite数据库。如果MATLAB使用数据库,Form-App应该重新启动(+ Countdown),直到MATLAB重置数据库中的忙位。 (仅供参考)

答案 20 :(得分:0)

您可以将代码封装在一个函数中,当需要重新启动时,您只需调用该函数即可。

答案 21 :(得分:0)

以一个应用程序为例:

  1. 未注册应用程序; (启动时)应用程序应提示用户注册该应用程序并创建一个登录帐户。

  2. 提交注册并创建登录凭证后,应用程序应该重新启动,检查注册并提示用户使用插入的凭据登录(以便用户可以访问所有应用程序功能)。

问题: 通过从Visual Studio构建和启动应用程序;以下四种选择中的任何一种都无法完成所需的任务。

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

会发生什么:创建注册后,登录并调用Application.Restart();。该应用程序将(奇怪地)重新打开注册表单并跳过数据库中的数据(即使资源设置为“如果更新则复制”)。

解决方案: 批处理构建应用程序(对我而言)是上述任何行均按预期运行的证明。 只是在使用Visual Studio构建和运行应用程序时没有。

首先,我将尝试批量构建应用程序;在Visual Studio外部运行它,并检查Application.Restart()是否确实按预期工作。

还要检查有关该主题的更多信息: How do I restart my C# WinForm Application?

相关问题