End a C# process with WPF

Asked

Viewed 2,456 times

4

I have a solution that has two projects. a main project and another that serves as Updater.

To perform the upgrade, within the main project, I call a console application as follows.

private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        //Lê arquivo xml e manipula arquivo xml
        XmlDocument doc = new XmlDocument();
        doc.Load("http://www.meusite.org.br/Cantina/arquivoXML.xml");
        XmlNode node = doc.DocumentElement.SelectSingleNode("/Application/Version");
        XmlNode node1 = doc.DocumentElement.SelectSingleNode("/Application/ZipFile");
        string version = node.InnerText;
        string zipfile = node1.InnerText;
        string End = (@"\\aps-serverweb\wwwroot\meusite.org.br\Cantina\");
        string file = (End + zipfile);
        string versionAssembly = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();

        //valida version (versão disponível no servidor para atualização) e versionAssembly (versão do sistema isntalado) 
        if (Convert.ToDouble(version) <= Convert.ToDouble(versionAssembly))
        {
           // MessageBox.Show("Sistema Atualizado" + version); 
        }
        else
        {
            //chama o projeto de atualiação de sistema console application IASD.ASCS.Updater
            Process myProc = Process.Start("Updater.exe");

        }
}

When calling the Updater (console application) process the following code is executed.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using Ionic.Zip;
using System.Xml;
using System;
using System.IO;
using Microsoft.VisualBasic;
using System.Threading;

namespace Updater
{
    class Program
    {
    static void Main(string[] args)
    {
        string nomeExecutavel = "IASD.ASCS.WPF.exe";
        foreach (Process pr in Process.GetProcessesByName(nomeExecutavel))
        {
            if (!pr.HasExited) pr.Kill();
        }

        //Lê e manipula arquivo xml com as informações do arquivo zip contendo a atualização disponível
        XmlDocument doc = new XmlDocument();
        doc.Load("http://www.meusite.org.br/Cantina/arquivoXML.xml");
        XmlNode node = doc.DocumentElement.SelectSingleNode("/Application/Version");
        XmlNode node1 = doc.DocumentElement.SelectSingleNode("/Application/ZipFile");
        string version = node.InnerText;
        string zipfile = node1.InnerText;
        string End = (@"\\aps-serverweb\wwwroot\meusite.org.br\Cantina\");
        string file = (End + zipfile);
        string versionAssembly = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();

        //Utiliza os métodos da biblioteca dotnetzip chamada Ionic.zip para baixar e extrair arquivos zip
        ZipFile zipFile = ZipFile.Read(file);
        {
            foreach (ZipEntry zipEntry in zipFile)
            {
                zipEntry.Extract(@"C:\IASD\CantinaEscolar\Temp\", ExtractExistingFileAction.OverwriteSilently);
            }
        }

        foreach (Process pr in Process.GetProcessesByName(nomeExecutavel))
        {
            if (!pr.HasExited) pr.Kill();
        }

        //Transfere os arquivos baixados no diretório Temp para o diretório instalação em c:\IASD\CantinaEscolar 
        string dirTemp = @"c:\IASD\CantinaEscolar\Temp";
        string dirInstalacao = @"c:\IASD\CantinaEscolar";
        string[] arquivos = Directory.GetFiles(dirTemp);
        foreach (string item in arquivos)
        {
            string nomedoarquivo = Path.GetFileName(item);
            string destino = Path.Combine(dirInstalacao, nomedoarquivo);
            File.Copy(item, destino, true);
        }
        string[] arquivosApagar = Directory.GetFiles(dirTemp);
        foreach (string item in arquivosApagar)
        {
            File.Delete(item);
        }

        foreach (Process pr in Process.GetProcessesByName(nomeExecutavel))
        {
            if (!pr.HasExited) pr.Start();
        }

        //Encerra o processo Updater
        string nomeExecutavel2 = "Updater.exe";
        foreach (Process pr2 in Process.GetProcessesByName(nomeExecutavel2))
           {
            if (!pr2.HasExited) pr2.Kill();
           }
       }
   }
}

The Updater basically does the following

  1. Closes the main proceedings

  2. Checks if you have an update available in the directory via an xml file. (This is also done in the main process to enter Updater).

  3. Unzip to a temporary folder.

  4. Copy to the installation folder of the main project.

  5. Deletes the files from the directory c:\IASD\CantinaEscolar\Temp

This works perfectly running inside the visual studio.

Now when installing the application on a computer, when copying the 'update' files from the Temp folder to the installation directory, an error is returned stating that the file is running.

The process needed to be terminated when running the application in Visual Studio is called IASD.ASCS.WPF.vshost. Already when the application is installed, the process changes name, becoming IASD.ASCS.WPF.exe which is the name of the project within Solution as well as the name of its executable that is in the folder bin\Debug.

I tried to end this process in the following ways and I did not succeed:

String nome = "IASD.ASCS.WPF.exe";
        // Obtém lista de processos
        Process[] processos = Process.GetProcesses();

        foreach (Process p in processos)
        {
            if (p.ProcessName.ToUpper() == nome.ToUpper())
            {
                // Tenta fechar a janela principal,
                // se falhar invoca o método Kill()
                if (!p.CloseMainWindow())
                {
                    p.Kill();
                }
                p.Close(); // Libera recursos associados.
            }
        }


        Process[] processes = Process.GetProcessesByName("Login.exe");

        foreach (Process process in processes)
        {
            process.Kill();
        }

        Process[] processes1 = Process.GetProcessesByName("Login");

        foreach (Process process1 in processes1)
        {
            process1.Kill();
        }

        Process[] processes2 = Process.GetProcessesByName("IASD.ASCS.WPF.exe");

        foreach (Process process2 in processes2)
        {
            process2.Kill();
        }

        Process[] processes3 = Process.GetProcessesByName("IASD.ASCS.WPF");

        foreach (Process process3 in processes3)
        {
            process3.Kill();
        }

        Process[] processes4 = Process.GetProcessesByName("vshost32");

        foreach (Process process4 in processes4)
        {
            process4.Kill();
        }

        Process[] processes5 = Process.GetProcessesByName("vshost32.exe");

        foreach (Process process5 in processes5)
        {
            process5.Kill();
        }

None of them work when the application is installed.

Note: The Login process cited in the code is the name of the WPF created as image of the Windows task manager:

inserir a descrição da imagem aqui

How could you terminate the IASD.ASCS.WPF.exe process for the application console to copy the files from the temp folder to the application installation folder and then restart this process?

2 answers

4

There is no way inside the main program, itself close, before calling the Updater?

// verifica se existe uma atualização
// e se existir, inicia o Updater.exe e depois se fecha
if (existeUmaAtualizacao)
{
    Process myProc = Process.Start("Updater.exe");
    Application.Current.Shutdown();
}

Inside Updater, you may need to try to delete the file from the original executable within a loop, until you can, with a timeout obviously, otherwise Updater might crash:

var timeout = DateTime.Now + TimeSpan.FromSeconds(30);
while (DateTime.Now < timeout)
{
    try
    {
        File.Delete("IASD.ASCS.WPF.exe");
        break;
    }
    catch { }
}

if (!File.Exists("IASD.ASCS.WPF.exe"))
{
    // arquivo foi excluido com sucesso,
    // agora podemos copiar o arquivo atualizado que está na pasta TEMP
}
  • It didn’t work. Includes string wpfExe = @"c: IASD Cantinaescola IASD.ASCS.WPF.exe"; File.Delete(wpfExe); Inside the Updater before the line that copies the files and even then appears the message that the IASD.ASCS.WPF.exe files are being executed by another process. In debugging the error returns at line 56, right in foreach: foreach (string item in files) string filename = Path.Getfilename(item); string destination = Path.Combine(dirInstallacao, filename); File.Copy(item, destination, true); }

  • In doing so, the application may be taking a while to close... so inside Updater, you may need to try several times to get access to the file, until it is released.

1

ATTENTION: Although I have already used/tested all these techniques, I have never built any application as I will describe here.

The executable IASD.ASCS.WPF.vshost.exe is the Visual Studio hosting process for this project. The function of this executable is to speed up the application debugging process avoiding the need to create a new process every time the application is run.

I’m not sure, but I assume that every execution where the executables have been modified, a new one is created application Domain to load the executables and run them. So that the executables can be modified even with the running program, I assume application Domain be it servant with shadow copy - the same process that ASP.NET uses.

If instead of a Updater you have a controller that launches your application in a application Domain separated with shadow copy you can control the application execution and update. In case an update has been made, the application Domain the current one is finished and a new one is created with minimum stop time. If there is a requirement to keep the application running, the same mechanism may be used to re-launch the application whenever the application Domain be terminated unexpectedly.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.