Инсталлятор с ожиданием завершения процесса.


      Данная статья описывает создание программы запуска «инсталляционных» файлов и отслеживание завершения, как основного, так и дочерних процессов создаваемых основным.
      Создайте приложение «Windows Form» в «Microsoft Visual Studio». Добавьте на главную форму созданного проекта, следующие элементы управления:
  • Button button1 – кнопка запуска выбранного файла;
  • ListBox listBox1 – лог отображения выполнения процессов;
  • Label label1 – обозначение текстового поля содержащего путь к исполняемому файлу;
  • Label label2 – обозначение текстового поля содержащего необходимые аргументы для запуска исполняемого файла;
  • TextBox textBox1 – текстовое поле, для ввода пути к исполняемому файлу;
  • TextBox textBox2 – текстовое поле, для ввода аргументов необходимых для запуска исполняемого файла;
  • BackgroundWorker backgroundWorker1 – компонент необходимый для запуска исполняемого файла с аргументами и отслеживания завершения как основного так и дочерних процессов в отдельном потоке.
      После добавления данных элементов управления у вас получится приведенный ниже пример главной формы вашего проекта.
      Выполните двойной клик правой клавишей мыши по элементу управления «button1». Вы перейдете в редактор кода с автоматически созданным методом «button1_Click». Добавьте в него приведенный ниже код блокировки кнопки «Запуск» и запуска исполняемого файла с аргументами и отслеживания завершения, как основного, так и дочерних процессов в отдельном потоке.
//Блокируем кнопку запуска исполняемого файла.
button1.Enabled = false;
//Запускаем выполнение фоновой операции.
backgroundWorker1.RunWorkerAsync();
      Перейдите в графический редактор главной формы вашего проекта и откройте события доступные для компонента «backgroundWorker1». Выполните двойной клик по событиям «DoWork» и «RunWorkerCompleted».
Ниже приведен код метода «backgroundWorker1_DoWork».
//Переменная для определения результата работы
//программы.
bool reseult_install = false;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    reseult_install = StartInstall(textBox1.Text, textBox2.Text);
}
Так же, код для метода «backgroundWorker1_RunWorkerCompleted».
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (reseult_install== true)
        debug("Работа процесса завершена успешно!");
    else
        debug("Работа процесса завершена с ошибками.");    
    //Работа программы завершена, выполняем разблокировку
    //кнопки запуска.
    button1.Enabled = true;
}
      Добавьте в листинг главной формы вашего проекта, приведенный ниже код, метода запуска и отслеживания завершения процесса.
private bool StartInstall(string FileSetup, string Arguments)
{
    //Переменная с результатом выполнения программы.
    bool result = false;

    try
    {
        //Инициализируем новый экземпляр класса System.Diagnostics.Process.
        Process StartProcess = new Process();   
        //Инициализируем новый экземпляр класса System.Diagnostics.ProcessStartInfo
        //и задаем аргументы, вместе с которыми должен
        //запускаться процесс.
        ProcessStartInfo startInfo = new ProcessStartInfo(FileSetup);
        //Задаем набор аргументов командной строки,
        // используемых при запуске приложения.
        if (Arguments != null || Arguments.Length > 0)
            startInfo.Arguments = Arguments;
        //Задаем свойства для передачи их методу System.Diagnostics.Process.Start()
        //объекта System.Diagnostics.Process.
        StartProcess.StartInfo = startInfo;
        //Запускаем (или начинаем заново использовать) ресурс процесса, определенный
        //свойством System.Diagnostics.Process.StartInfo 
        //этого компонента System.Diagnostics.Process.
        StartProcess.Start();
        //Выводим информацию о работе программы
        debug("Успешный запуск процесса");                
        debug("Имя процесса: "+StartProcess.ProcessName);                
        debug("Идентификатор: "+StartProcess.Id);
        //Даем System.Diagnostics.Process команду ожидать неопределенно
        //долго до завершения связанного процесса.
        StartProcess.WaitForExit();
        debug("Основной процесс завершён!");
        //Получаем значение, определяющее завершение связанного процесса.
        if (StartProcess.HasExited)
        {
            result = true;
            debug("Связанный процесс завершён!");
        }
        else
            result = false;              

        try
        {
            debug("Поиск дочерних процессов для " + StartProcess.Id);
            //Запускаем процесс отслеживания дочерних процессов.
            WaitAllProcesses((UInt32)StartProcess.Id);
        }
        catch (Exception ex)
        {
            debug("Ошибка поиска дочерних процессов...");
            //В случае возникновения ошибки, выводим ее в лог.
            debug(ex.Message);
            result = false;
        }
    }
    catch (Exception ex)
    {
        result = false;
    }

    return result;
}

private void WaitAllProcesses(UInt32 parentProcessId)
{
    debug(String.Format("Поиск дочерних процессов [{0}]", parentProcessId));

    //Выполняем поиск процессов с указанием идентификатора процесса,
    //породившего данный процесс.
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(
        String.Format("SELECT * FROM Win32_Process WHERE ParentProcessId={0}", parentProcessId));
    //Вызываем заданный WMI-запрос и получаем результирующую коллекцию.
    ManagementObjectCollection collection = searcher.Get();
    //Если найдены дочерние процессы, то идем дальше.
    if (collection.Count > 0)
    {
        debug(String.Format("Найдено {0} дочерних процессов", collection.Count));
        debug(String.Format("главного процесса с идентификатором [{0}]", parentProcessId));
        //Выполняем проход по всей коллекции.
        foreach (var item in collection)
        {
            //Получаем индентификатор текущего дочернего процесса.
            UInt32 childProcessId = (UInt32)item["ProcessId"];

            if ((int)childProcessId != Process.GetCurrentProcess().Id)
            {
                //Запускаем поиск дочерних процессов для текущего 
                //дочернего процесса.
                WaitAllProcesses(childProcessId);
                //Получаем новый компонент System.Diagnostics.Process, c заданным
                //идентификатором процесса на локальном компьютере.
                Process childProcess = Process.GetProcessById((int)childProcessId);
                debug(String.Format("Ожидание дочернего процесса [{0}]", childProcess.ProcessName));
                debug(String.Format("с идентификатором [{0}]", childProcessId));
                //Даем System.Diagnostics.Process команду ожидать неопределенно
                //долго до завершения связанного процесса.
                childProcess.WaitForExit();
            }
        }
    }
}

//Так как отслеживание завершения процесса будет
//выполняться в другом потоке, то для доступа к логу
//необходимо выполнить указанный делегат асинхронно в потоке,
//в котором был создан базовый дескриптор
//элемента управления.
public void debug(string text)
{
    try
    {
        if (this.InvokeRequired)
            BeginInvoke(new MethodInvoker(delegate
            {
                listBox1.Items.Add(String.Format("[{0}] {1}", DateTime.Now, text));
            }));
        else
        {
            listBox1.Items.Add(String.Format("[{0}] {1}", DateTime.Now, text));
        }
    }
    catch (Exception ex)
    {
        listBox1.Items.Add(String.Format("[{0}] {1}", DateTime.Now, ex.Message));
    }
}
      Запустите проект, укажите путь к исполняемому файлу и аргументы при необходимости. Нажмите кнопку «Запуск» и отслеживайте изменения в логе программы.

Комментариев нет:

Отправить комментарий

Большая просьба, не писать в комментариях всякую ерунду не по теме!