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 publicApplication.Exit()
method, eliding some security checks/asserts.See if it can determine the
Assembly.GetEntryAssembly()
. If that isnull
the call theApplication.Restart()
was most likely done from unmanaged code and the operation throws aNotSupportedException
to the caller.See if the current process is
ieexec.exe
, if so use it to restart the application (for more information aboutieexec.exe
see here). Actually that is pretty much also aProcess.Start()
call toieexec.exe
, but the command line arguments are not gathered byEnvironment.GetCommandLineArgs()
(see below), but by reading theAPP_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'sCreateProcess
API).Else: the application is a "regular" .NET application.
Environment.GetCommandLineArgs()
is used to recreate the original command line andProcess.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:
- Use a user setting to remember the state. For example, call it
RestartedOnUpdate
and set it totrue
before callingApplication.Restart()
. Set it to false after you've restarted. - Instead of using
Application.Restart()
you could useProcess.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:
- Create a setting like
SettingsUpgradeNeeded
and set it totrue
in the designer. It will then be published like that to the client. - In the
Main
method check whether the setting istrue
and perform a settings upgrade. - 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
How to Export a Jqgrid Data to Excel Using C#
Posting JSON Data to ASP.NET MVC
How to Flatten Nested Objects with Linq Expression
How to Update Values into Appsetting.JSON
Is Inaccessible Due to Its Protection Level
Displaying Arabic Characters in C# Console Application
Double Buffering When Not Drawing in Onpaint(): Why Doesn't It Work
Why Can't I Use System.Io.File Methods in an MVC Controller
Wpf: How to Override Part of a Controltemplate Without Redefining the Whole Style
How to Restrict/Control the Navigation Routes the User Can Visit Based on Login Status/Role
C# - Detect Time of Last User Interaction with the Os
No Connection String Named 'Myentities' Could Be Found in the Application Config File
Why Are C# 4 Optional Parameters Defined on Interface Not Enforced on Implementing Class