Desenvolvimento - C#
Manipulando processos através da classe System.Diagnostics.Process
Este artigo mostra o uso da classe System.Diagnostics.Process através de exemplos de como criar e matar um processo, como redirecionar a saída da execução de um processo, como detectar o término de um processo e, ao final, como sair de um processo.
por Renato GuimarãesEssa pode ser uma situação fácil de você encontrar qualquer dia, ou seja, como criar ou gerenciar processos através de sua aplicação .NET. Sendo assim, resolvi escrever um pequeno artigo para ensiná-los o pouco (dá pra fazer um monte de coisas legais) do que aprendi a fazer utilizando a classe System.Diagnostics.Process. Para isso, vou implementar alguns exemplos onde mostro como criar e matar um processo, como redirecionar a saída da execução de um processo, como detectar o término de um processo e, ao final, como sair de um processo. Um boa parte da explicação do que vou fazer estará dentro do próprio exemplo. Nos exemplos vou fazer referência a uma aplicação console que escreve algumas mensagens no console e, caso seja passado alguns parâmetros, exibe-os no console. Na listagem 1 mostra o código da aplicação console.
Listagem 1 - Aplicação console que escreve algumas mensagens no console e, caso sejam passados parâmetros, escreve-os no console.
using System; class AplicacaoConsole{ static void Main(string[] args){ if ((args != null) && (args.Length> 0)){ Console.WriteLine("Parâmetros passados para aplicação"); for (int i = 0; i < args.Length; i++){ Console.WriteLine(args[i]); } }else { Console.WriteLine("Aplicação console não recebeu parâmetros"); } for (int i = 1; i <= 400; i++){ if (i % 10 == 0){ Console.WriteLine(i); }else { Console.Write( i.ToString().PadLeft(3, " ") + " "); } } } }
Listagem 2 - Criando e matando um processo. Para isso, vamos executar a aplicação da listagem 1.
using System; using System.Threading; using System.Diagnostics; public class CriarMatarProcesso{ static void Main(string[] args){ try{ //O método estático Start cria um novo processo. Além do método //start, também podemos criar um objeto do tipo Process usando //um construtor e passar os parâmetros do processo. Process proc = Process.Start("c:\\AplicacaoConsole.exe"); Console.WriteLine("Executando a aplicação console...."); //Para que der tempo de vermos a aplicação executando, vamos dar //uma pausa de 6 segundos na aplicação para que seja possível ver o //console que foi aberto com a aplicação AplicacaoConsole.exe. Thread.Sleep(6000); //Matando o processo que iniciado em Process.Start. Com esse método //estaremos fechando a tela do console que foi aberta proc.Kill(); Console.WriteLine("Matou o processo. A outra janela console é fechada."); Console.ReadLine(); }catch (Exception ex){ Console.WriteLine(ex.StackTrace); } } }
Listagem 3 - Redireciona a saída de um processo. Às vezes você pode ter a necessidade de recuperar a saída do processo para ser feita alguma análise.
using System; using System.Diagnostics; public class RedirecionaSaidaProcesso{ static void Main(string[] args){ try{ //Criando um objeto do tipo Process e passando os parâmetros para //inicialização do processo. Process proc = new Process(); proc.StartInfo.FileName = "c:\\AplicacaoConsole.exe"; //Argumentos que serão para a aplicação informada em FileName proc.StartInfo.Arguments = "VS.NET - A melhor ferramenta RAD"; //Indica se o processo deve ou não usar um shell do SO proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; proc.Start(); //Imprimindo o resultado da execução do processo. String saidaProcesso = proc.StandardOutput.ReadToEnd(); //Só mata o processo caso ele ainda esteja executando if (proc.HasExited == false) { proc.Kill(); } Console.WriteLine("========================================="); Console.WriteLine("Saída retornada pela execução do processo"); Console.WriteLine("========================================="); Console.WriteLine(" "); Console.WriteLine(saidaProcesso); Console.ReadLine(); }catch(Exception ex){ Console.WriteLine(ex.StackTrace); } } }
Listagem 4 - Detecta a conclusão de um processo. Nas listagens 1 e 2 criei os processos e, em seguida, os matei sem ter certeza se eles já tinham terminado. Ou seja, precisamos saber se um processo já foi concluído antes de eliminá-lo. Para isso, o .NET tem um manipulador de evento que permite você saber quando um processo tiver terminado. Vou fazer o mesmo exemplo da listagem 2 e adicionar um método para manipular o evento. Podemos identificar de duas formas o término do processo. A primeira utilizando o meto WaitForExit; a segunda usando um manipulador para o evento Exited.
using System; using System.Diagnostics; public class DetectaConclusaoProcesso{ static void Main(string[] args){ try{ //Criando um objeto do tipo Process e passando os parâmetros para //inicialização do processo. Process proc = new Process(); proc.StartInfo.FileName = "c:\\AplicacaoConsole.exe"; proc.StartInfo.Arguments = "Bem vindo ao Sharp Shooters.NET"; proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; //Permitindo o lançamento de eventos proc.EnableRaisingEvents = true; //Registrando o manipulador para o evento Exited proc.Exited += new EventHandler(ProcessoConcluido); proc.Start(); //Imprimindo o resultado da execução do processo. String saidaProcesso = proc.StandardOutput.ReadToEnd(); //Matando o processo. Console.WriteLine("========================================="); Console.WriteLine("Saída retornada pela execução do processo"); Console.WriteLine("========================================="); Console.WriteLine(" "); Console.WriteLine(saidaProcesso); //Indica que deve esperar até o processo ser concluído proc.WaitForExit(); Console.ReadLine(); }catch(Exception ex){ Console.WriteLine(ex.StackTrace); } } private static void ProcessoConcluido(object sender, EventArgs e){ Console.WriteLine("Processo concluído"); } }
Listagem 5 - Lista um conjunto de processos pelo nome e lista todos os processos. O que vimos até agora é só um pouco do que pode ser possível fazer com a classe Process. Além dos métodos que vimos, ela possui métodos que nos permite recuperar todos os processos ou fazer um filtro pelo nome. Vamos implementar o código para listar todos os processos do SO e, em seguida, listar todos os processos do Internet Explorer.
using System; using System.Diagnostics; public class PesquisandoProcessos{ static void Main(string[] args){ try{ //O código abaixo recupera a lista de todos os processos e, em seguida, lista //as propriedades de cada um. Console.WriteLine("Listando todos os processos"); Process[] todosProc = Process.GetProcesses(); foreach (Process processo in todosProc){ ListarDadosProcess(processo); } Console.WriteLine("Listando todos os processos do Internet Explorer"); //O código abaixo recupera a lista de todos os processos abertos com IE Process[] processosIE = Process.GetProcessesByName("iexplore"); foreach (Process processo in processosIE){ ListarDadosProcess(processo); } Console.ReadLine(); }catch(Exception ex){ Console.WriteLine(ex.StackTrace); } } static void ListarDadosProcess(Process processo) { Console.WriteLine("ID..............: " + processo.Id); Console.WriteLine("Nome............: " + processo.ProcessName); Console.WriteLine("Está respondendo? " + processo.Responding); Console.WriteLine("Nome Máquina....: " + processo.MachineName); Console.WriteLine("Nome Arquivo....: " + processo.StartInfo.FileName); Console.WriteLine("Argumentos......: " + processo.StartInfo.Arguments); Console.WriteLine("Dir. Trabalho...: " + processo.StartInfo.WorkingDirectory); Console.WriteLine("Verb............: " + processo.StartInfo.Verb); Console.WriteLine("Tam. Mem. Virtual.........: " + processo.VirtualMemorySize); Console.WriteLine("Tempo Utiliz. Processador.: " + processo.TotalProcessorTime); Console.WriteLine("Tam. Mem. Física Utilizada: " + processo.WorkingSet); Console.WriteLine(" "); } }
Resultado do código da listagem 5:
Listando todos os processos ID..............: 532 Nome............: winlogon Est respondendo? True Nome M quina....: . Nome Arquivo....: Argumentos......: Dir. Trabalho...: Verb............: Tam. Mem. Virtual.........: 52654080 Tempo Utiliz. Processador.: 00:00:26.0781250 Tam. Mem. F¡sica Utilizada: 3678208 ID..............: 1384 Nome............: ConTEXT Est respondendo? True Nome M quina....: . Nome Arquivo....: Argumentos......: Dir. Trabalho...: Verb............: Tam. Mem. Virtual.........: 33964032 Tempo Utiliz. Processador.: 00:00:11.6250000 Tam. Mem. F¡sica Utilizada: 7016448 ... ID..............: 0 Nome............: Idle Est respondendo? True Nome M quina....: . Nome Arquivo....: Argumentos......: Dir. Trabalho...: Verb............: Tam. Mem. Virtual.........: 0 Tempo Utiliz. Processador.: 10.22:21:24.6562500 Tam. Mem. F¡sica Utilizada: 20480 Listando todos os processos do Internet Explorer ID..............: 980 Nome............: iexplore Est respondendo? True Nome M quina....: . Nome Arquivo....: Argumentos......: Dir. Trabalho...: Verb............: Tam. Mem. Virtual.........: 360644608 Tempo Utiliz. Processador.: 00:02:50.9062500 Tam. Mem. F¡sica Utilizada: 54591488
Bem, acho que com esses exemplos já dá pra fazer muita coisa legal. Acho que a classe Process é uma das provas que vale a pena mudar para .NET. Veja que com poucas linhas de código conseguimos fazer coisas que, em outras linguagens, creio fosse preciso um esforço muito grande. Assim que tiver um tempinho livre, dê uma estudada nos outros métodos e propriedades da classe System.Diagnostics.Process para aprofundar seus conhecimentos. Grande abraço e espero vocês no próximo...