C # - Il riavvio dell'applicazione è in conflitto con l'errore "programma già in esecuzione"
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());
}
}
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