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!
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo