Why Is Application.Restart() Not Reliable

Why is Application.Restart() not reliable?

There could be a lot of reasons for this. It's not that the method doesn't work; rather, many times programmers forget that they've put something in their code that would stop the application from automatically shutting down, or starting up. Two examples:

  • The Closing event on a form can stop an app's shutdown
  • If you're doing checking for an already-running process, the old one may not be closing fast enough to allow the new one to start up.

Check your code for gotchas like that. If you're seeing this behaviour within a blank application, then that's more likely to be a problem with the actual function than your code.

Check Microsoft's sourcecode of application restart.

Is Application.Restart bad?

Not friendly to debug, but there's nothing really wrong with it. It is the exact same as terminating the app and starting it again.

You can avoid it by simply creating a new instance of your main form and closing the old one. That however does require you to prevent the program from exiting. Code is here.

My Application.Restart Doesn't Complete?

So thanks to the link from above I found a recommendation on a different thread that was a great workaround to simply using the Application.Restart() method.

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

It allows my program to restart very effectively in spite of my closing validation.
This would probably still be an issue if I did any closing validation related to the Application.Exit call.

Application.Restart leaves processes hanging

Environment.Exit(0) is the API equivalent of ExitProcess(0) in kernel32.dll. It terminates the process immediately. Both Application.Exit and Application.Restart can hang while the main thread is processing.

For your case I suggest using Environment.Exit and start a new instance before that:

System.Diagnostics.Process.Start(Application.ExecutablePath);
Environment.Exit(0)

This will definitely exit your application.

How do I restart my C# WinForm Application?

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..."

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.)

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)

How do I run some methods and functions of an application after restarting the application automatically

You can create a flag in application settings and then process it on startup:

//Set a flag on restart
Properties.Settings.Default.IsRestarting = true;
Properties.Settings.Default.Save();
Application.Restart();

...
//Process it on startup (e.g. Main method or Form.Load event for the main form)
if(Properties.Settings.Default.IsRestarting)
{
// run some commands and change some variables here
Properties.Settings.Default.IsRestarting = false;
Properties.Settings.Default.Save();
}

Alternatively, you can store this flag anywhere you want: file system, registry, database, etc.

You can also, use Process.Start instead of Application.Restart to run another instance of your app. This way you can interact with a new process: send command line arguments, pass messages.

Also, see: Why is Application.Restart() not reliable?

How does Application.Restart work in .NET?

... not being fluent with IL, ...

Have you considered using a decompiler (Reflector, dotPeek) or, even better, the reference source code of the .NET framework?

Anyway.

At a casual look it does the following:

  • In all below cases, the current instance is terminated using Application.ExitInternal(). That is the gist of the public Application.Exit() method, eliding some security checks/asserts.

  • See if it can determine the Assembly.GetEntryAssembly(). If that is null the call the Application.Restart() was most likely done from unmanaged code and the operation throws a NotSupportedException to the caller.

  • See if the current process is ieexec.exe, if so use it to restart the application (for more information about ieexec.exe see here). Actually that is pretty much also a Process.Start() call to ieexec.exe, but the command line arguments are not gathered by Environment.GetCommandLineArgs() (see below), but by reading the APP_LAUNCH_URL application domain data.

  • See if the application is a click-once application (ApplicationDeployment.IsNetworkDeployed), if so call an CLR internal native code to (re)launch that: CorLauncApplication. The only publicly available source code that somewhat resembles the native parts of the CLR is the shared source CLI (sscli), which is based on the .NET 2.0 framework and also is partly incomplete. It contains a definition for that function (clr\src\vm\hosting.cpp), but it is only a stub. In the end it will use some means to restart the process (e.g. Win32's CreateProcess API).

  • Else: the application is a "regular" .NET application. Environment.GetCommandLineArgs() is used to recreate the original command line and Process.Start(Application.ExecutablePath) is used to restart the application.

The use of the Application.Exit-mechanism to try to end the current instance is probably the reason why you find it unreliable. Forms that cancel the send closing event can interrupt it. Also see this SO question.

Know when application was opened with Application.Restart()

There's no way you could do this out of the box. Two possible solutions come to my mind:

  1. Use a user setting to remember the state. For example, call it RestartedOnUpdate and set it to true before calling Application.Restart(). Set it to false after you've restarted.
  2. Instead of using Application.Restart() you could use Process.Start() and supply some kind of command line argument (like /updated).

Actually it is good practise to perform a settings update after doing a ClickOnce update, so that user settings that were changed are not reset to their default values.

The general approach to that is:

  1. Create a setting like SettingsUpgradeNeeded and set it to true in the designer. It will then be published like that to the client.
  2. In the Main method check whether the setting is true and perform a settings upgrade.
  3. Set the setting to false so no upgrade happens next run.

You could use that flag to check whether you started for the first time after a ClickOnce update.

Restart an application by itself

I use similar code to the code you tried when restarting apps. I send a timed cmd command to restart the app for me like this:

ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C ping 127.0.0.1 -n 2 && \"" + Application.ExecutablePath + "\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Application.Exit();

The command is sent to the OS, the ping pauses the script for 2-3 seconds, by which time the application has exited from Application.Exit(), then the next command after the ping starts it again.

Note: The \" puts quotes around the path, incase it has spaces, which cmd can't process without quotes.

Hope this helps!



Related Topics



Leave a reply



Submit