views:

88

answers:

2

I am trying to restart an application in WPF.

I tried the following:

Process.Start(Application.ExecutablePath);
Process.GetCurrentProcess().Kill();

And it doesn't work because the application is setup as a single instances application.

Then I tired this:

Process.GetCurrentProcess().Kill();
Process.Start(Application.ExecutablePath);

And it doesn't work because once we Kill the process it will not hit line 2

Is there a way to schedule a the .Start so that I don't run into issue #1.

+2  A: 

You could launch a secondary application that would then re-launch your main program after the delay. When I wrote a self-updater a few years ago, that was the implementation path that I took. It was just a simple program that took the executable as a command line arg, would sleep for a tenth of a second, then .Start it.

A better implementation path than I took would be to have the newly-launched program wait for the process that launched it to terminate. Waiting the arbitrary length of time could complicate matters. In order to accomplish this, I would probably pass the process ID to the re-launcher so that it would know exactly which process to wait on.

JustLoren
You probably should wait for the old process to terminate instead of waiting an arbitrary amount of time (which may, or may not be enough for the application to close). Especially if cleanup hits a few page faults shutting down an application can take longer than you originally anticipate.
Joey
That's a fair point. A better solution would do the monitoring as you suggest.
JustLoren
Thank you for your suggestion. I saw this solution awhile ago but this seems messy. But I guess there isn't a good way to do it without writing a "restarter" program.
Chi Chan
+1  A: 

It's not as hard as you think. All you need to do is call the following method, passing in the command line for the restarted instance:

public static void RestartMe(string commandLine)
{
  var myId = Process.GetCurrentProcess().Id;
  var myPath = Assembly.GetEntryAssembly().CodeBase.Replace("file:///", "");
  var systemPath = typeof(object).Assembly.CodeBase.Replace("file:///", "");

  var tempPath = Path.GetTempFileName();

  File.WriteAllText(tempPath + ".cs", @"
    using System;
    using System.Diagnostics;
    public class App
    {
      public static void Main(string[] args)
      {
        try { Process.GetProcessById(" + myId + @").WaitForExit(); } catch {}
        Process.Start(""" + myPath + @""", Environment.CommandLine);
      }
    }");

  var compiler = new ProcessStartInfo
  {
    FileName = Path.Combine(Path.GetDirectoryName(systemPath), "csc.exe"),
    Arguments = tempPath + ".cs",
    WorkingDirectory = Path.GetDirectoryName(tempPath),
    WindowStyle = ProcessWindowStyle.Hidden,
  };

  var restarter = new ProcessStartInfo
  {
    FileName = tempPath + ".exe",
    Arguments = commandLine,
    WindowStyle = ProcessWindowStyle.Hidden,
  };

  Process.Start(compiler).WaitForExit();
  Process.Start(restarter); // No WaitForExit: restarter WaitForExits us instead

  File.Delete(tempPath);
  File.Delete(tempPath + ".cs");
  Environment.Exit(0);
}

How it works: This actually does create another "restarter" program but does it painlessly and automatically. The restarter program has the current process id and the executable filename built right into it. It will always find the compiler because NET Framework version ships with a compatible csc.exe in the same folder as System.dll.

Ray Burns