开发者

C# - Restarting application conflicts with "program already running" error

开发者 https://www.devze.com 2022-12-10 00:24 出处:网络
When I call the Application.Restart() method, the error comes up that detects whether the application is currently running.Is there anyway around this?

When I call the Application.Restart() method, the error comes up that detects whether the application is currently running. Is there anyway around this?

    static void Main(string[] args)
    {
        string proc = Process.GetCurrentProcess().ProcessName;
        Process[] processes = Process.GetProcessesByName(proc);
        if (processes.Length > 1)
        {
            MessageBox.Show("Program is already running.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Applica开发者_StackOverflowtion.Run(new Form1());
        }
    }


Use a Mutex. e.g.: A Single Instance Application which Minimizes to the System Tray when Closed. This example is more complex than you probably need, but the basic single instance concept of using a Mutex works well.


The most effective way to do this is to inherit from VB.Net's WindowsFormsApplicationBase class, which can also be used in C#, and set the IsSingleInstance property to true. This uses a mutex and will continue working if the EXE file is renamed.


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.

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

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 StreamWriter here would be held open until process really dies. Then...

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:

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


Try hooking up your restart code to the Application.ApplicationExit event as a listener method. Then you will call Application.Exit to cause the code to run indirectly.

Edit: Added code sample:

For example, when the user clicks the restart button or the app decides to restart, call this RestartMeSmartly() method. You won't have to worry about trickery - it will work.

void RestartMeSmartly() {
    Application.ApplicationExit += BeforeExiting;
    Application.Exit();
}

void BeforeExiting(object sender, EventArgs args) {
    Application.Restart();
}


The simplest way to do this is to add a delay before quiting.

In other words,

string proc = Process.GetCurrentProcess().ProcessName;
if (Process.GetProcessesByName(proc).Length > 1) {
    Thread.Sleep(500);      //500 milliseconds; you might need to wait longer
    if (Process.GetProcessesByName(proc).Length > 1) {
        MessageBox.Show("Program is already running.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }
}    //no else
0

精彩评论

暂无评论...
验证码 换一张
取 消