Usando CreateProcess para se integrar com aplicativos externos

Usando CreateProcess para se integrar com aplicativos externos, neste artigo de Daniel Wildt. Acesso exclusivo para Assinantes.

Usando CreateProcess para se integrar com aplicativos externos

 

Introdução

Falamos em outra dica sobre o uso do ShellExecute, para abrir aplicações externas. A questão é que apesar do comando ShellExecute ser extremamente poderoso, as vezes queremos mais. Exemplo, queremos executar uma aplicação externa e esperar esta terminar, para então continuarmos o nosso processamento.

Nesta dica iremos trabalhar com a função CreateProcess da API do Windows, onde iremos criar um processo (que será abrir o notepad para editar um arquivo) e faremos nossa aplicação ficar esperando o processo criado ser finalizado.

2. A estrutura do Comando

O comando CreateProcess tem a seguinte assinatura:

function CreateProcess(lpApplicationName: PChar; lpCommandLine: PChar; lpProcessAttributes, lpThreadAttributes: PSecurityAttributes; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: PChar; const lpSta

 

Onde:

lpApplicationName: Aplicação que deve ser executada. Exemplo, Notepad.exe. lpCommandLine: Se você preferir, pode colocar NIL no primeiro parâmetro e neste parâmetro indicar a aplicação e parâmetros. Exemplo indicar Notepad.exe e o arquivo que o mesmo tem que abrir.

lpProcessAttributes: Não vamos tratar neste exemplo, deixe NIL.

lpThreadAttributes: Não vamos tratar neste exemplo, deixe NIL.

bInheritHandles: Não vamos tratar neste exemplo, deixe FALSE.

dwCreationFlags: Permite especificar algumas flags para a criação do processo. Exemplo CREATE_SUSPENDED (permite criar o processo "parado", de modo que o programador pode configurar o ponto ideal para colocar o processo em execução. Por padrão o processo é criado e colocado em execução. Neste parâmetro é possível também configurar a prioridade do processo, exemplo REALTIME_PRIORITY_CLASS, que indica que o novo processo deve ser executado com a mais alta das prioridades. Outros valores referentes a prioridades são NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS e IDLE_PRIORITY_CLASS.

lpEnvironment: Não vamos tratar neste exemplo, deixe NIL.

lpCurrentDirectory: Indica o diretório corrente para o processo que está sendo criado.

lpStartupInfo: Esta estrutura define parâmetros que indicam como a janela do processo que está sendo criado vai aparecer. Podemos citar alguns atributos relevantes para o nosso processo:

cb: Tamanho da estrutura. Utilizei 2048 como exemplo.

lpReserved e lpReserved2: atribuir NIL para estes parâmetros.

lpDesktop: deixar NIL neste parâmetro, utilizaremos configurações do processo pai.

lpTitle: pode ser colocado o nome que deve aparecer na janela do Console DOS. Caso a aplicação executada seja visual, se pode passar NIL no parâmetro.

dwFlags: aqui pode se indicar uma série de parâmetros como STARTF_USESHOWWINDOW (indica parâmetro para abertura de tela), STARTF_USEPOSITION (permite especificar atributos dwX w dwY da estrutura, com as posições iniciais da janela), STARTF_USESIZE (permite indicar o tamanho da tela através dos atributos dwXSize e dwYSize).

wShowWindow: indica o padrão da abertura da janela, como SW_SHOWNORMAL, SW_SHOWMAXIMIZED e SW_SHOWMINIMIZED.

lpProcessInformation: Esta estrutura é a chave da dica, pois é com ela que iremos monitorar a execução do processo filho e é através dela que saberemos quando o mesmo terminou. Esta estrutura possui identificadores do processo e da Thread, através dos atributos disponibilizados na estrutura do record TProcessInformation.

3. Aplicação de Exemplo

Iremos construir uma aplicação que permite selecionar um arquivo .txt ou .pas e feita esta seleção poderemos acionar um botão chamado "Create Process".

 

Este botão irá criar um outro processo (Notepad - Bloco de Notas) e vai ficar aguardando a janela ser fechada para deixar a nossa aplicação continuar. Assim que a janela do Notepad é aberta, é criada uma tela na nossa aplicação de exemplo indicando para o usuário aguardar o fechamento da aplicação. O que esta tela de apoio faz é possuir um timer e a cada ocorrência do evento de timer é realizado um teste para identificar se o processo criado ainda está ativo. Se o processo não está mais ativo, a janela de apoio é fechada.

 

Veja o click do botão para criar o processo, com os comentários de apoio:

procedure TFormPrincipal.btnCreateProcessClick(Sender: TObject);

var

   lStartUpInfo:TStartUpInfo;

   lProcesso: TProcessInformation;

begin

 

   // Inicializa a estrutura TStartUpInfo

   // indicando formato de abertura da janela

   // e setando os atributos obrigatórios

   // de serem inicializados.

With lStartUpInfo do

begin

cb:=2048;

   lpReserved:=NIL;

   lpDesktop:=NIL;

lpTitle:=NIL;

dwFlags:=STARTF_USESHOWWINDOW;

wShowWindow:=SW_SHOWNORMAL;//SW_Hide; //para não aparecer na tela!

   cbReserved2:=0;

lpReserved2:=NIL;

end;

 

// Cria o processo notepad.exe e passa por

// parâmetro o arquivo a ser aberto.

// Passa também as estruturas de controle,

// lStartUpInfo e lProcesso.

if not CreateProcess(NIL,PChar('notepad.exe ' + edArquivo.Text),

NIL, NIL, False, 0, NIL, PChar(ExtractFilePath(edArquivo.Text)),

lStartUpInfo, lProcesso) then

ShowMessage('Erro para executar CreateProcess')

else

begin

 

// Abre tela de apoio para aguardar o

// término do processo recém criado.

// A tela de apoio fica testando

// o status do processo, através da

// função da API do Windows, chamada

// GetExitCodeProcess

 

FormAguardar := TFormAguardar.Run(Self, lProcesso);

try

    FormAguardar.ShowModal;

finally

   FormAguardar.Free;

end;

end;

end;

 

O método Run da classe TFormAguardar é um construtor que recebe o parâmetro Owner e a variável de status do processo, para que seja possível realizar consultas.  Assim que a tela é aberta e o evento de timer começa a ser acionado, é verificado  o status do processo que foi executado. Veja o fonte do código do Timer:

procedure TFormAguardar.TimerTimer(Sender: TObject);

var

lExitCode: dword;

begin

MoveLabel;

 

// Testa se Processo ainda está ativo...

// Continua rodando o timer enquanto o status

// for diferente de STILL_ACTIVE, que indica que

// o processo está ativo.

 

if GetExitCodeProcess(FProcesso.hProcess, lExitCode) then

if (lExitCode<>STILL_ACTIVE) then

close;

end;

4. Conclusões

Com esta dica verificamos como trabalhar com a função CreateProcess, para iniciar um processo externo e monitorar o término do mesmo. Veja o exemplo para download que permite que você selecione arquivos e execute e teste a abertura de um processo.

Por hoje era isto pessoal. Até a próxima!

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados