93

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

Application.Restart();

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

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

4

22 回答 22

87

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

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

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

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

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

于 2011-02-23T03:08:34.970 回答
56

如果您处于主应用程序形式,请尝试使用

System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app
于 2010-09-17T16:47:37.147 回答
40

不幸的是,您不能使用 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, "");
    }

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

于 2009-09-09T03:22:30.210 回答
18

我可能迟到了,但这是我的简单解决方案,它对我拥有的每个应用程序都很有效:

        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
        { }
于 2011-11-24T01:26:42.747 回答
15

我有同样的问题,我也有防止重复实例的要求——我提出了一个替代解决方案来替代 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
   }
}

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

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

于 2010-01-07T14:13:17.937 回答
7

启动/退出方法

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

于 2009-04-22T21:54:06.093 回答
6

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

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

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

Application.Exit();
System.Diagnostics.Process.Start(Application.ExecutablePath);
于 2013-04-01T07:26:31.137 回答
4

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

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

代码已简化,因此请注意异常和其他东西;)

于 2016-06-24T10:21:11.243 回答
3

试试这个代码:

bool appNotRestarted = true;

此代码也必须在函数中:

if (appNotRestarted == true) {
    appNotRestarted = false;
    Application.Restart();
    Application.ExitThread();
}
于 2011-07-27T11:28:52.340 回答
2

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

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

于 2009-04-23T04:34:50.810 回答
2

您也可以使用Restarter

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

于 2011-04-09T09:21:02.267 回答
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 );
}
于 2012-06-07T08:37:45.523 回答
2

我担心使用 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;
           }
        }
    }
于 2014-02-20T22:10:59.663 回答
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返回您的应用程序 .exe 文件路径 请按照调用顺序。您可能希望将其放在 try-catch 子句中。

于 2016-07-01T09:25:10.423 回答
1

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

批处理文件执行此操作:

  1. 循环等待以检查进程是否已退出。
  2. 开始这个过程。
于 2011-12-15T01:54:38.463 回答
1

这是我的 2 美分:

序列 Start New Instance->Close Current Instance 即使对于不允许同时运行多个副本的应用程序也应该有效,因为在这种情况下,可能会向新实例传递一个命令行参数,该参数将指示正在重新启动因此不需要检查其他正在运行的实例。如果绝对没有两个实例并行运行是绝对必要的,那么等待第一个实例实际完成我的实现也是如此。

于 2012-03-27T15:42:40.623 回答
1

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

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

而且效果很好。在我的例子中,MATLAB 和一个 C# 应用程序共享同一个 SQLite 数据库。如果 MATLAB 正在使用数据库,Form-App 应该再次重新启动(+倒计时),直到 MATLAB 重置其在数据库中的忙位。(仅供参考)

于 2017-02-15T15:50:50.193 回答
0

我遇到了类似的问题,但我的问题与无法管理的内存泄漏有关,我在必须 24/7 运行的应用程序上找不到该问题。我与客户同意,如果内存消耗超过定义值,则重新启动应用程序的安全时间是凌晨 03:00。

我试过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);
    }
}
于 2011-04-09T09:11:23.257 回答
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);
}
于 2015-10-28T16:16:36.070 回答
0

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

//点击注销按钮

foreach(Form frm in Application.OpenForms.Cast<Form>().ToList())
        {
            frm.Close();
        }
System.Diagnostics.Process.Start(Application.ExecutablePath);
于 2015-12-31T05:09:02.180 回答
0

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

于 2019-07-13T15:01:01.180 回答
0

以一个应用程序为例:

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

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

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

/*
 * 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() 是否确实按预期工作。

另请检查有关此线程主题的更多信息: 如何重新启动我的 C# WinForm 应用程序?

于 2020-12-02T13:30:31.080 回答