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ães



Outro dia um amigo meu chegou pra mim e disse: "kbça, tem como eu construir uma aplicação Windows com .NET que faça chamadas a uma aplicação console que eu fiz em Delphi? " Na mesma hora lembrei que outro dia fiz uns testes com a classe System.Diagnostics.Process e disse: Caro colega desconhecedor do poder do .net, diz o que queres que vou te mostrar como irás fazer em poucas linhas de código. JJJJ

Essa 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...

Renato Guimarães

Renato Guimarães - Bacharel em Sistemas de Informação e trabalha com tecnologia da informação há mais de 15 anos.