C # - Il riavvio dell'applicazione è in conflitto con l'errore "programma già in esecuzione"

StackOverflow https://stackoverflow.com/questions/1647811

  •  22-07-2019
  •  | 
  •  

Domanda

Quando chiamo il metodo Application.Restart (), viene visualizzato l'errore che rileva se l'applicazione è attualmente in esecuzione. C'è comunque qualcosa attorno a questo?

    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);
            Application.Run(new Form1());
        }
    }
È stato utile?

Soluzione

Il modo più efficace per farlo è ereditare da WindowsFormsApplicationBase , che può essere utilizzato anche in C # e imposta la proprietà IsSingleInstance su true . Questo utilizza un mutex e continuerà a funzionare se il file EXE viene rinominato.

Altri suggerimenti

Usa un Mutex. ad es .: Un'applicazione a istanza singola che riduce al minimo nella barra delle applicazioni quando è chiusa . Questo esempio è più complesso di quanto probabilmente ti serva, ma il concetto di base a singola istanza di usare un Mutex funziona bene.

Ho avuto un problema simile, ma il mio era legato a una perdita di memoria ingestibile che non riuscivo a trovare su un'app che doveva funzionare 24 ore su 24, 7 giorni su 7. Con il cliente ho concordato che il tempo sicuro per riavviare l'app era 03:00 se il consumo di memoria era superiore al valore definito.

Ho provato Application.Restart , ma dato che sembra usare un meccanismo che avvia una nuova istanza mentre è già in esecuzione, ho optato per un altro schema. Ho usato il trucco che il file system gestisce persistere fino a quando il processo che li ha creati non è morto. Quindi, da The Application, ho lasciato cadere il file sul disco e non ho Dispose () l'handle. Ho usato il file per inviare eseguibile 'me stesso' e anche avviare la directory (per aggiungere flessibilità).

Codice:

_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 () alla fine avvierebbe l'arresto dell'app, e l'handle di file che ho usato per StreamWriter qui sarebbe tenuto aperto fino a quando il processo non fosse realmente morto. Quindi ...

Restarter.exe entra in azione. PROVA a leggere il file in modalità esclusiva, impedendogli di accedere fino a quando l'app principale non è morta, quindi avvia l'app principale, elimina il file ed esiste. Immagino che non possa essere più semplice:

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

Prova a collegare il tuo codice di riavvio a Evento Application.ApplicationExit come metodo di ascolto. Quindi chiamerai Application.Exit per far sì che il codice venga eseguito indirettamente.

Modifica : esempio di codice aggiunto:

Ad esempio, quando l'utente fa clic sul pulsante di riavvio o l'app decide di riavviare, chiama questo metodo RestartMeSmartly (). Non dovrai preoccuparti di inganno - funzionerà.

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

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

Il modo più semplice per farlo è aggiungere un ritardo prima di uscire.

In altre parole,

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top