Как перезапустить приложение c# WinForm?


разработка приложения WinForm на C# .NET 2.0. Нужно приложение, чтобы закрыть и перезапустить себя.

Application.Restart();

приведенный выше метод имеет оказался ненадежным.

что является лучшим способом, чтобы перезапустить приложение?

20 71

20 ответов:

к сожалению вы не можете использовать процесс.Метод start() для запуска экземпляра процесса. Согласно процессу.Пуск() документы: "Если процесс уже запущен, дополнительный ресурс процесса не запускается..."

этот метод будет отлично работать под отладчиком VS (потому что VS делает какую-то магию, которая вызывает процесс.Начните думать, что процесс еще не запущен), но потерпит неудачу, когда не запускается под отладчиком. (Обратите внимание, что это может быть OS-specific-I кажется, помните, что в некоторых из моих тестов он работал либо на XP, либо на Vista, но я могу просто помнить, что он работает под отладчиком.)

этот метод точно используется последним программистом в проекте, над которым я сейчас работаю, и я уже довольно давно пытаюсь найти обходной путь для этого. До сих пор я нашел только одно решение, и он просто чувствует себя грязным и kludgy для меня: запустите 2-е приложение, которое ждет в фоновом режиме для первого приложения чтобы завершить, затем повторно запускает 1-е приложение. Я уверен, что это сработает, но, тьфу.

Edit: использование 2-го приложения работает. Все, что я сделал во втором приложении было:

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

(Это очень упрощенный пример. Настоящий кодекс имеет множество санитарные проверки, обработки ошибок и т. д.)

Если вы находитесь в основной форме приложения попробуйте использовать

System.Diagnostics.Process.Start( Application.ExecutablePath); // to start new instance of application
this.Close(); //to turn off current app

гораздо более простой подход, который работал для меня:

Application.Restart();
Environment.Exit(0);

это сохраняет аргументы командной строки и работает, несмотря на обработчики событий, которые обычно предотвращают закрытие приложения.

вызов Restart () пытается выйти, запускает новый экземпляр в любом случае и возвращает. Затем вызов Exit () завершает процесс, не давая ни одному обработчику событий возможности запуска. Существует очень короткий период, в течение которого оба процесса работают, что не является проблемой в мой случай, но, возможно, в других случаях.

код выхода 0 в Environment.Exit(0); указывает чистое завершение работы. Вы также можете выйти с 1, чтобы указать произошла ошибка.

Я могу опоздать на вечеринку, но вот мое простое решение, и оно работает как шарм с каждым приложением, которое у меня есть:

        try
        {
            //run the program again and close this one
            Process.Start(Application.StartupPath + "\blabla.exe"); 
            //or you can use Application.ExecutablePath

            //close this one
            Process.GetCurrentProcess().Kill();
        }
        catch
        { }

у меня была такая же точная проблема, и у меня тоже было требование предотвратить дублирование экземпляров - я предлагаю альтернативное решение для того, что предлагает HiredMind (который будет работать нормально).

то, что я делаю, это запуск нового процесса с processId старого процесса( тот, который запускает перезапуск) в качестве аргумента строки cmd:

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

затем, когда новое приложение запускается, я сначала разбираю строки cm args и проверяю, есть ли флаг перезапуска с processId, затем дождитесь завершения этого процесса:

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

Я, очевидно, не показываю все проверки безопасности, которые у меня есть на месте и т. д.

даже если не идеально - я нахожу это допустимой альтернативой, так что вам не нужно иметь на месте отдельное приложение только для обработки перезагрузки.

его просто нужно просто позвонить Application.Restart() методы, которые, как правило, вызывают у вас приложение для перезапуска. Но вы должны выйти из локальной среды с их кодами ошибок:

Application.Restart();
Environment.exit(int errorcode);

вы можете создать перечисление кодов ошибок, которые вы можете использовать его эффективно.
другой способ - просто выйти из приложения и запустить процесс, имеющий исполняемый путь:

Application.exit();
System.Diagnostics.Process.Start(Application.ExecutablePath);

Метод Запуска/Выхода

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

Это, кажется, работает лучше, чем приложение.Перезагрузка();

не уверен, как это работает, если ваша программа защищает от нескольких экземпляров. Я думаю, что вам было бы лучше запустить второй .exe, который приостанавливает, а затем запускает ваше основное приложение для вас.

попробуйте этот код:

bool appNotRestarted = true;

этот код должен быть в функции:

if (appNotRestarted == true) {
    appNotRestarted = false;
    Application.Restart();
    Application.ExitThread();
}

Я придумал другое решение, возможно, кто-то может использовать его тоже.

string batchContent = "/c \"@ECHO OFF & timeout /t 6 > nul & start \"\" \"$[APPPATH]$\" & exit\"";
batchContent = batchContent.Replace("$[APPPATH]$", Application.ExecutablePath);
Process.Start("cmd", batchContent);
Application.Exit();

код упрощен, поэтому позаботьтесь об исключениях и прочее;)

вы забываете параметры командной строки / параметры, которые были переданы в ваш текущий экземпляр. Если вы не передадите их, вы не сделаете настоящий перезапуск. Установите Process.StartInfo с клоном параметры процесса, а затем сделать старт.

например, если процесс был запущен как myexe -f -nosplash myfile.txt, ваш метод будет выполняться только myexe без всех этих флагов и параметров.

Я хотел, чтобы новое приложение запускалось после завершения работы старого.

через процесса.WaitForExit() ждать завершения собственного процесса не имеет смысла. Это всегда будет тайм-аут.

Итак, мой подход заключается в использовании приложения.Exit () затем подождите, но позвольте событиям обрабатываться в течение определенного периода времени. Затем запустите новое приложение с теми же аргументами, что и старое.

static void restartApp() {
    string commandLineArgs = getCommandLineArgs();
    string exePath = Application.ExecutablePath;
    try {
        Application.Exit();
        wait_allowingEvents( 1000 );
    } catch( ArgumentException ex ) {
        throw;
    }
    Process.Start( exePath, commandLineArgs );
}

static string getCommandLineArgs() {
    Queue<string> args = new Queue<string>( Environment.GetCommandLineArgs() );
    args.Dequeue(); // args[0] is always exe path/filename
    return string.Join( " ", args.ToArray() );
}

static void wait_allowingEvents( int durationMS ) {
    DateTime start = DateTime.Now;
    do {
        Application.DoEvents();
    } while( start.Subtract( DateTime.Now ).TotalMilliseconds > durationMS );
}

вы также можете использовать Рестартеры.

Restarter-это приложение, которое автоматически отслеживает и перезапускает разбитые или зависшие программы и приложения. Он был первоначально разработан для мониторинга и перезагрузки игровых серверов, но он будет выполнять эту работу для любой консоли или формы на основе программы или приложения

public static void appReloader()
    {
        //Start a new instance of the current program
        Process.Start(Application.ExecutablePath);

        //close the current application process
        Process.GetCurrentProcess().Kill();
    }

приложение.ExecutablePath возвращает свое применение .путь к файлу exe Пожалуйста, следите за порядком звонков. Вы можете поместить его в предложение try-catch.

вот мои 2 цента:

последовательность Start New Instance - >Close Current Instance должна работать даже для приложений, которые не позволяют запускать несколько копий одновременно, так как в этом случае новому экземпляру может быть передан аргумент командной строки, который укажет, что выполняется перезапуск, поэтому проверка других запущенных экземпляров не потребуется. Ожидание первого экземпляра, чтобы фактически завершить мою реализацию, если это абсолютно необходимо, чтобы нет две интстанции работают параллельно.

Я боюсь, что перезапуск всего приложения с помощью процесса приближается к вашей проблеме в неправильном направлении.

наиболее простой способ-это изменить программу.cs-файл для перезапуска:

    static bool restart = true; // A variable that is accessible from program
    static int restartCount = 0; // Count the number of restarts
    static int maxRestarts = 3;  // Maximum restarts before quitting the program

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        while (restart && restartCount < maxRestarts)
        {
           restart = false; // if you like.. the program can set it to true again
           restartCount++;  // mark another restart,
                            // if you want to limit the number of restarts
                            // this is useful if your program is crashing on 
                            // startup and cannot close normally as it will avoid
                            // a potential infinite loop

           try {
              Application.Run(new YourMainForm());
           }
           catch {  // Application has crashed
              restart = true;
           }
        }
    }

у меня была аналогичная проблема, но моя была связана с неуправляемой утечкой памяти, которую я не мог найти в приложении, которое должно работать 24/7. С клиентом я согласился, что безопасное время для перезапуска приложения было 03: 00 утра, если потребление памяти было более определенного значения.

пробовал Application.Restart, но так как он, кажется, использует какой-то механизм, который запускает новый экземпляр, пока он уже запущен, я пошел на другую схему. Я использовал трюк, что дескрипторы файловой системы сохраняются до тех пор, пока процесс, который созданный им умирает. Итак, из приложения я сбросил файл на диск и не сделал Dispose() ручки. Я использовал файл для отправки исполняемого файла " сам " и стартового каталога также (чтобы добавить гибкость).

код:

_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() в конце будет инициировать завершение работы приложения, и дескриптор файла я использовал для StreamWriter здесь будет открыт до тех пор, пока процесс действительно не умрет. Затем...

Рестартеры.exe вступает в действие. Он пытается прочитать файл в эксклюзивном режиме, предотвращение доступа к нему до тех пор, пока основное приложение не будет мертвым, затем запускает основное приложение, удаляет файл и существует. Я думаю, что это не может быть проще:

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

Как насчет создания файла bat, запустите пакетный файл перед закрытием, а затем закройте текущий экземпляр.

пакетный файл это:

  1. подождите в цикле, чтобы проверить, вышел ли процесс.
  2. запустить процесс.

Я использую следующее, И он делает именно то, что вы ищете:

ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
UpdateCheckInfo info = null;
info = ad.CheckForDetailedUpdate();
if (info.IsUpdateRequired)
{
    ad.UpdateAsync(); // I like the update dialog
    MessageBox.Show("Application was upgraded and will now restart.");
    Environment.Exit(0);
}

для использования в качестве выхода из системы вам нужно завершить все приложения из кэша оперативной памяти поэтому сначала закройте приложение, а затем снова запустите его

//при нажатии кнопки выхода из системы

foreach(Form frm in Application.OpenForms.Cast<Form>().ToList())
        {
            frm.Close();
        }
System.Diagnostics.Process.Start(Application.ExecutablePath);

проблема использования приложение.Перезагрузка() это то, что он начинает новый процесс, но "старый" все еще остается. Поэтому я решил убить старый процесс, используя следующий фрагмент кода:

            if(Condition){
            Application.Restart();
            Process.GetCurrentProcess().Kill();
            }

и он работает правильно хорошо. В моем случае MATLAB и приложение C# используют одну и ту же базу данных SQLite. Если MATLAB использует базу данных, приложение формы должно перезапустить (+обратный отсчет) снова, пока MATLAB не сбросит свой бит занятости в базе данных. (Только для стороны информация)