views:

6470

answers:

5

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

Application.Restart();

The above method has proven to be unreliable.

What is a better way to restart the application?

+1  A: 

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

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.

Adam Nofsinger
That might not work if application is protected from multiple instances.
majkinetor
@majkinetor - Noted in updated answer to question.
Adam Nofsinger
Yah, I have a feeling calling Application.Exit() only causes some message to be added to a queue somewhere that needs to be pumped, so the second bit of code here in my answer probably would indeed not work.
Adam Nofsinger
Unfortunately this technique doesn't work (I wish it did! It's so much more simple than my solution). It will work inside the Visual Studio debugger but not in practice. See my answer for a kludgy solution that works outside the debugger.
HiredMind
HiredMind might be right. I ended up going with a Watchdog pattern solution.
Adam Nofsinger
+3  A: 

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.StartInfo with a clone of your process' parameters, then do a start.

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

Erich Mirabal
I updated my answer to address this issue.
Adam Nofsinger
+5  A: 

The selected answer doesn't work. 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)

HiredMind
I agree with HiredMind, and I actually went with the same "Watchdog program" implementation myself shortly after writing the answer. Sorry, should have come back here and updated.I wouldn't think it should feel _too_ horribly ugly/yucky/dirty. The Watchdog program pattern is pretty widely used.
Adam Nofsinger
+1  A: 

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

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:

// 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:

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.

JohnIdol
A: 

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
Darqer
-1 too similar to other answers
John Saunders
It is similar, but different. Application.Exit didn't work form me, and this.Close() did the job.
Darqer