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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/779405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 00:51:05  来源:igfitidea点击:

How do I restart my C# WinForm Application?

c#.net

提问by Adam Nofsinger

Developing a C# .NET 2.0 WinForm Application. Need the application to close and restart itself.

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

Application.Restart();

The above method has proven to be unreliable.

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

What is a better way to restart the application?

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

采纳答案by HiredMind

Unfortunately you can't use Process.Start() to start an instance of the currently running process. According to the Process.Start() docs: "If the process is already running, no additional process resource is started..."

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

This technique will work fine under the VS debugger (because VS does some kind of magic that causes Process.Start to think the process is not already running), but will fail when not run under the debugger. (Note that this may be OS-specific - I seem to remember that in some of my testing, it worked on either XP or Vista, but I may just be remembering running it under the debugger.)

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

This technique is exactly the one used by the last programmer on the project on which I'm currently working, and I've been trying to find a workaround for this for quite some time. So far, I've only found one solution, and it just feels dirty and kludgy to me: start a 2nd application, that waits in the background for the first application to terminate, then re-launches the 1st application. I'm sure it would work, but, yuck.

这种技术正是我目前正在从事的项目的最后一位程序员所使用的技术,并且我一直在寻找解决方法已有一段时间了。到目前为止,我只找到了一个解决方案,对我来说只是觉得又脏又笨:启动第二个应用程序,它在后台等待第一个应用程序终止,然后重新启动第一个应用程序。我确定它会起作用,但是,糟糕。

Edit: Using a 2nd application works. All I did in the second app was:

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

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

(This is a very simplified example. The real code has lots of sanity checking, error handling, etc)

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

回答by Adam Nofsinger

Start/Exit Method

启动/退出方法

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

This seems to work better than Application.Restart();

这似乎比 Application.Restart(); 效果更好。

Not sure how this handles if your program protects against multiple instance. My guess is you would be better off launching a second .exe which pauses and then starts your main application for you.

如果您的程序防止多个实例,则不确定如何处理。我的猜测是你最好启动第二个 .exe,它会暂停然后为你启动你的主应用程序。

回答by Erich Mirabal

You are forgetting the command-line options/parameters that were passed in to your currently running instance. If you don't pass those in, you are not doing a real restart. Set the Process.StartInfowith a clone of your process' parameters, then do a start.

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

For example, if your process was started as myexe -f -nosplash myfile.txt, your method would only execute myexewithout all those flags and parameters.

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

回答by JohnIdol

I had the same exact problem and I too had a requirement to prevent duplicate instances - I propose an alternative solution to the one HiredMind is proposing (which will work fine).

我有同样的问题,我也有防止重复实例的要求 - 我提出了一个 HiredMind 提出的替代解决方案(这将正常工作)。

What I am doing is starting the new process with the processId of the old process (the one that triggers the restart) as a cmd line argument:

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

Then when the new app starts I first parse the cm line args and check if the restart flag is there with a processId, then wait for that process to Exit:

然后当新应用程序启动时,我首先解析 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
   }
}

I am obviously not showing all the safety checks that I have in place etc.

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

Even if not ideal - I find this a valid alternative so that you don't have to have in place a separate app just to handle restart.

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

回答by Darqer

If you are in main app form try to use

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

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

回答by EMP

A much simpler approach that worked for me is:

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

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

This preserves the command-line arguments and works despite event handlers that would normally prevent the application from closing.

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

The Restart() call tries to exit, starts a new instance anyway and returns. The Exit() call then terminates the process without giving any event handlers a chance to run. There is a very brief period in which both processes are running, which is not a problem in my case, but maybe in other cases.

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

The exit code 0 in Environment.Exit(0);specifies a clean shutdown. You can also exit with 1 to specify an error occurred.

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

回答by Daniel Mo?mondor

I had a similar problem, but mine was related to unmanageable memory leak that I couldn't find on an app that has to run 24/7. With the customer I agreed that safe time to restart the app was 03:00AM if the memory consumption was over the defined value.

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

I tried Application.Restart, but since it seems to use some mechanism that starts new instance while it is already running, I went for another scheme. I used the trick that file system handles persist until process that created them dies. So, from The Application, i dropped the file to the disk, and didn't Dispose()the handle. I used the file to send 'myself' executable and starting directory also (to add flexibility).

我试过了Application.Restart,但由于它似乎使用了某种机制,在它已经运行时启动新实例,我选择了另一种方案。我使用了文件系统处理持续到创建它们的进程死亡的技巧。因此,从应用程序中,我将文件放到了磁盘上,但没有删除Dispose()句柄。我还使用该文件发送了“我自己”的可执行文件和起始目录(以增加灵活性)。

Code:

代码:

_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()at the end would initiate app shutdown, and file handle I used for StreamWriterhere would be held open until process really dies. Then...

Close()最后将启动应用程序关闭,并且我在StreamWriter这里使用的文件句柄将保持打开状态,直到进程真正终止。然后...

Restarter.exe comes into action. It TRIES to read the file in exclusive mode, preventing it to gain access until main app wasn't dead, then starts main app, deletes the file and exists. I guess that it can't be simpler:

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

回答by Daniel Rose

You could also use Restarter.

您也可以使用Restarter

Restarter is an application that automatically monitor and restarts crashed or hung programs and applications. It was originally developed to monitor and restart game servers, but it will do the job for any console or form based program or application

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

回答by ferhatayhan

Try this code:

试试这个代码:

bool appNotRestarted = true;

This code must also be in the function:

此代码也必须在函数中:

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

回答by SolidSnake

I might be late to the party but here is my simple solution and it works like a charm with every application I have:

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

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