Difference between revisions of "Executing External Programs/pt"
m (Fixed syntax highlighting) |
|||
(8 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
== Introdução == | == Introdução == | ||
− | Existem | + | Existem várias formas de executar um programa externo, mas eu destacarei apenas uma. TProcess. |
+ | |||
+ | Se você sempre usou '''ShellExecute''' e/ou '''WinExec''' em Delphi, então você pode começar a usar TProcess como uma alternativa em FPC/Lazarus (isso é válido também se você está executando Lazarus em um Linux, porque TProcess é multi-plataforma). | ||
+ | |||
+ | '''Nota:''' FPC/Lazarus tem suporte à '''ShellExecute''' e/ou '''WinExec''', mas este suporte é somente em Win32. Se o seu programa é multi-plataforma, então use TProcess, é o melhor caminho! | ||
+ | |||
+ | == SysUtils.ExecuteProcess == | ||
+ | |||
+ | O caminho mais simples se você não necessita de "pipes" ou qualquer outro controle é simplesmente usar SysUtils.ExecuteProcess('/full/path/to/binary',['arg1','arg2']); | ||
==TProcess== | ==TProcess== | ||
Você pode usar TProcess para iniciar programas externos. Alguns dos beneficios de usar TProcess: | Você pode usar TProcess para iniciar programas externos. Alguns dos beneficios de usar TProcess: | ||
− | * | + | *Plataforma Independente |
− | * Capacidade de leitura da | + | *Capacidade de leitura da saída e escrita da entrada. |
+ | |||
+ | Nota: TProcess não é um terminal/shell! Você não pode executar diretamente scripts ou redirecionar a saida usando operadores como "|", ">", "<", "&" etc. É possível obter o mesmo resultado com TProcess usando pascal, alguns exemplos estão a seguir.. | ||
===Um Exemplo Simples=== | ===Um Exemplo Simples=== | ||
− | + | <syntaxhighlight lang=pascal> | |
// Este é um programa de demonstração que mostra como executar | // Este é um programa de demonstração que mostra como executar | ||
// um programa externo. | // um programa externo. | ||
Line 50: | Line 60: | ||
AProcess.Free; | AProcess.Free; | ||
end. | end. | ||
+ | </syntaxhighlight> | ||
É isso! Você aprendeu razoavelmente como executar um programa externo de dentro do seu próprio programa. | É isso! Você aprendeu razoavelmente como executar um programa externo de dentro do seu próprio programa. | ||
Line 58: | Line 69: | ||
Bom, vamos expandir nosso exemplo um pouco e faremos apenas isso: | Bom, vamos expandir nosso exemplo um pouco e faremos apenas isso: | ||
+ | <syntaxhighlight lang=pascal> | ||
// Este é um programa que mostra como executar | // Este é um programa que mostra como executar | ||
// um programa externo e ler sua saída. | // um programa externo e ler sua saída. | ||
Line 113: | Line 125: | ||
AProcess.Free; | AProcess.Free; | ||
end. | end. | ||
+ | </syntaxhighlight> | ||
===Lendo a grande saida=== | ===Lendo a grande saida=== | ||
− | No exemplo anterior nós esperamos enquanto o programa finalizava. | + | No exemplo anterior nós esperamos enquanto o programa finalizava. Então nós lemos o que o programa escreveu em sua saida. Mas suponhamos que o programa escreva uma série de dados para a saída, os "pipes" virão carregados e precisam ser lidos. Mas chamando o programa não lerá dele, enquanto o programa chamado não finalizar. Um fechamento inoperante acontecerá. |
− | Então nós lemos | ||
− | Mas suponhamos que o programa escreva uma série de dados para a saída, | ||
− | os "pipes" virão carregados e precisam ser lidos. | ||
− | Mas chamando o programa não lerá dele, enquanto o programa chamado não finalizar. | ||
− | Um fechamento inoperante | ||
− | O exemplo seguinte então não usa o poWaitOnExit, mas lê a saida, enquanto o programa tranquilamente é executado. | + | O exemplo seguinte então não usa o poWaitOnExit, mas lê a saida, enquanto o programa tranquilamente é executado. A saida é armazenada no fluxo de memória, que pode depois ser usado para ler a saida em uma TStringList. |
− | A saida é armazenada no fluxo de memória | ||
− | + | <syntaxhighlight lang=pascal> program procoutlarge; | |
{ | { | ||
Copyright (c) 2004 by Marc Weustink | Copyright (c) 2004 by Marc Weustink | ||
Line 162: | Line 169: | ||
P.CommandLine := 'ppc386 -va bogus.pp'; | P.CommandLine := 'ppc386 -va bogus.pp'; | ||
P.Options := [poUsePipes]; | P.Options := [poUsePipes]; | ||
− | WriteLn('-- | + | WriteLn('-- executando --'); |
P.Execute; | P.Execute; | ||
while P.Running do | while P.Running do | ||
Line 195: | Line 202: | ||
if BytesRead > 0 then WriteLn; | if BytesRead > 0 then WriteLn; | ||
M.SetSize(BytesRead); | M.SetSize(BytesRead); | ||
− | WriteLn('-- | + | WriteLn('-- executado --'); |
S := TStringList.Create; | S := TStringList.Create; | ||
S.LoadFromStream(M); | S.LoadFromStream(M); | ||
− | WriteLn('-- | + | WriteLn('-- número de linhas = ', S.Count, ' --'); |
for n := 0 to S.Count - 1 do | for n := 0 to S.Count - 1 do | ||
begin | begin | ||
WriteLn('| ', S[n]); | WriteLn('| ', S[n]); | ||
end; | end; | ||
− | WriteLn('-- | + | WriteLn('-- final --'); |
S.Free; | S.Free; | ||
P.Free; | P.Free; | ||
M.Free; | M.Free; | ||
− | end. | + | end.</syntaxhighlight> |
+ | |||
+ | === Usando a entrada e saida de um TProcess === | ||
+ | Veja o exemplo processemo no [https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/examples/process Lazarus-CCR SVN]. | ||
+ | |||
+ | === Dicas no uso de TProcess === | ||
+ | Se você está criando um programa multi-plataforma, você pode mudar a linha de comando de acordo com o SO (Sistema Operacional), usando diretivas "{$IFDEF}s" and "{$ENDIF}s". | ||
+ | |||
+ | Exemplo: | ||
+ | <syntaxhighlight lang=pascal> {...} | ||
+ | AProcess:TProcess.Create(nil) | ||
+ | {$IFDEF WIN32} | ||
+ | AProcess.CommandLine := 'calc.exe'; //Calculadora do Windows | ||
+ | {$ENDIF} | ||
+ | {$IFDEF LINUX} | ||
+ | AProcess.CommandLine := 'kcalc'; //Calculadora do KDE | ||
+ | {$ENDIF} | ||
+ | AProcess.Execute; //em alternativa, você pode usar AProcess.Active:=True | ||
+ | {...}</syntaxhighlight> | ||
+ | |||
− | === | + | === Exemplo de "conversa" com um processo aspell === |
− | + | Dentro do código-fonte do [http://pasdoc.sourceforge.net/ pasdoc] você pode encontrar duas units que executam 'spell-checking' por uma conversa com o processo aspell em execução através de "pipes": | |
− | * [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_ProcessLineTalk.pas PasDoc_ProcessLineTalk.pas | + | * [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_ProcessLineTalk.pas A unit PasDoc_ProcessLineTalk.pas] implementa a classe TProcessLineTalk, descendente de TProcess, que pode ser facilmente usada para conversar com qualquer processo em uma base de linha-por-linha. |
− | * [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_Aspell.pas PasDoc_Aspell.pas | + | * [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_Aspell.pas A unit PasDoc_Aspell.pas] implementa a classe TAspellProcess, que executa 'spell-checking' pela utilização de uma instância subjacente TProcessListTalk para executar aspell e comunicar com o processo aspell em execução. |
− | + | Ambas as units são um pouco independentes do resto dos fontes pasdoc, assim elas pode servir como exemplos reais da utilização de TProcess para executar comunicação através de pipes com outros programas. |
Latest revision as of 12:58, 14 February 2020
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
italiano (it) │
日本語 (ja) │
Nederlands (nl) │
polski (pl) │
português (pt) │
русский (ru) │
slovenčina (sk) │
中文(中国大陆) (zh_CN) │
Introdução
Existem várias formas de executar um programa externo, mas eu destacarei apenas uma. TProcess.
Se você sempre usou ShellExecute e/ou WinExec em Delphi, então você pode começar a usar TProcess como uma alternativa em FPC/Lazarus (isso é válido também se você está executando Lazarus em um Linux, porque TProcess é multi-plataforma).
Nota: FPC/Lazarus tem suporte à ShellExecute e/ou WinExec, mas este suporte é somente em Win32. Se o seu programa é multi-plataforma, então use TProcess, é o melhor caminho!
SysUtils.ExecuteProcess
O caminho mais simples se você não necessita de "pipes" ou qualquer outro controle é simplesmente usar SysUtils.ExecuteProcess('/full/path/to/binary',['arg1','arg2']);
TProcess
Você pode usar TProcess para iniciar programas externos. Alguns dos beneficios de usar TProcess:
- Plataforma Independente
- Capacidade de leitura da saída e escrita da entrada.
Nota: TProcess não é um terminal/shell! Você não pode executar diretamente scripts ou redirecionar a saida usando operadores como "|", ">", "<", "&" etc. É possível obter o mesmo resultado com TProcess usando pascal, alguns exemplos estão a seguir..
Um Exemplo Simples
// Este é um programa de demonstração que mostra como executar
// um programa externo.
program launchprogram;
// Aqui são incluidos arquivos que terão funções úteis
// e procedures que nós precisamos.
uses
Classes, SysUtils, Process;
// Este ponto é definida a variável "AProcess" como uma variável
// do tipo "TProcess"
var
AProcess: TProcess;
// Aqui é onde o nosso programa inicia a execução
begin
// Agora nós criaremos o objeto TProcess, e
// associamos ele à variável AProcess.
AProcess := TProcess.Create(nil);
// Mostraremos ao novo AProcess qual é o comando para ele executar.
// Vamos usar o Compilador FreePascal
AProcess.CommandLine := 'ppc386 -h';
// Nós definiremos uma opção para onde o programa
// é executado. Esta opção verificará que nosso programa
// não continue enquanto o programa que nós executamos
// não pare de executar. vvvvvvvvvvvvvv
AProcess.Options := AProcess.Options + [poWaitOnExit];
// Agora que AProcess sabe qual é a linha de comando
// nós executaremos ele.
AProcess.Execute;
// Esta parte não é alcançada enquanto ppc386 não parar a execução.
AProcess.Free;
end.
É isso! Você aprendeu razoavelmente como executar um programa externo de dentro do seu próprio programa.
Um Exemplo aperfeiçoado
Isso é bom, mas como eu leio a saida de um programa que eu executei?
Bom, vamos expandir nosso exemplo um pouco e faremos apenas isso:
// Este é um programa que mostra como executar
// um programa externo e ler sua saída.
program launchprogram;
// Aqui são incluidos arquivos que terão funções úteis
// e procedures que nós precisamos.
uses
Classes, SysUtils, Process;
// Neste ponto é definida a variável "AProcess" como uma variável
// do tipo "TProcess"
// Também agora nós adicionamos uma TStringList para armazenar os
// dados lidos da saida do programa.
var
AProcess: TProcess;
AStringList: TStringList;
// Aqui é onde o nosso programa inicia a execução
begin
// Agora nós criaremos o objeto TProcess, e
// associamos ele à variável AProcess.
AProcess := TProcess.Create(nil);
// Cria o objeto TStringList.
AStringList := TStringList.Create;
// Mostraremos ao novo AProcess qual é o comando para ele executar.
// Vamos usar o Compilador FreePascal
AProcess.CommandLine := 'ppc386 -h';
// Nós definiremos uma opção para onde o programa
// é executado. Esta opção verificará que nosso programa
// não continue enquanto o programa que nós executamos
// não pare de executar. Também agora vamos mostrar a ele que
// que nós precisamos ler a saída do arquivo.
AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
// Agora que AProcess sabe qual é a linha de comando
// nós executaremos ele.
AProcess.Execute;
// Esta parte não é alcançada enquanto ppc386 não parar a execução.
// Agora lida a saida do programa nós colocaremos
// ela na TStringList.
AStringList.LoadFromStream(AProcess.Output);
// Salvamos a saida para um arquivo.
AStringList.SaveToFile('output.txt');
// Agora que o arquivo foi salvo nós podemos liberar a
// TStringList e o TProcess.
AStringList.Free;
AProcess.Free;
end.
Lendo a grande saida
No exemplo anterior nós esperamos enquanto o programa finalizava. Então nós lemos o que o programa escreveu em sua saida. Mas suponhamos que o programa escreva uma série de dados para a saída, os "pipes" virão carregados e precisam ser lidos. Mas chamando o programa não lerá dele, enquanto o programa chamado não finalizar. Um fechamento inoperante acontecerá.
O exemplo seguinte então não usa o poWaitOnExit, mas lê a saida, enquanto o programa tranquilamente é executado. A saida é armazenada no fluxo de memória, que pode depois ser usado para ler a saida em uma TStringList.
program procoutlarge;
{
Copyright (c) 2004 by Marc Weustink
This example is creeated in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}
uses
Classes, Process, SysUtils;
const
READ_BYTES = 2048;
var
S: TStringList;
M: TMemoryStream;
P: TProcess;
n: LongInt;
BytesRead: LongInt;
begin
// Nós não podemos usar poWaitOnExit aqui visto que nós não
// conhecemos o tamanho da saída. No Linux o tamanho do
// pipe de saida é 2 kB. Se os dados da saída são maiores, nós
// precisamos ler os dados. Isto não é possível visto que nós estamos
// esperando. Deste modo nós recebemos um deadlock aqui.
//
// Uma Memorystream temporária é usada para armazenar a saida
M := TMemoryStream.Create;
BytesRead := 0;
P := TProcess.Create(nil);
P.CommandLine := 'ppc386 -va bogus.pp';
P.Options := [poUsePipes];
WriteLn('-- executando --');
P.Execute;
while P.Running do
begin
// Verifica se temos dependências
M.SetSize(BytesRead + READ_BYTES);
// tenta ler ela
n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
if n > 0
then begin
Inc(BytesRead, n);
Write('.')
end
else begin
// sem dados, espera 100 ms
Sleep(100);
end;
end;
// lê a última parte
repeat
// verifica se temos dependências
M.SetSize(BytesRead + READ_BYTES);
// try reading it
n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
if n > 0
then begin
Inc(BytesRead, n);
Write('.');
end;
until n <= 0;
if BytesRead > 0 then WriteLn;
M.SetSize(BytesRead);
WriteLn('-- executado --');
S := TStringList.Create;
S.LoadFromStream(M);
WriteLn('-- número de linhas = ', S.Count, ' --');
for n := 0 to S.Count - 1 do
begin
WriteLn('| ', S[n]);
end;
WriteLn('-- final --');
S.Free;
P.Free;
M.Free;
end.
Usando a entrada e saida de um TProcess
Veja o exemplo processemo no Lazarus-CCR SVN.
Dicas no uso de TProcess
Se você está criando um programa multi-plataforma, você pode mudar a linha de comando de acordo com o SO (Sistema Operacional), usando diretivas "{$IFDEF}s" and "{$ENDIF}s".
Exemplo:
{...}
AProcess:TProcess.Create(nil)
{$IFDEF WIN32}
AProcess.CommandLine := 'calc.exe'; //Calculadora do Windows
{$ENDIF}
{$IFDEF LINUX}
AProcess.CommandLine := 'kcalc'; //Calculadora do KDE
{$ENDIF}
AProcess.Execute; //em alternativa, você pode usar AProcess.Active:=True
{...}
Exemplo de "conversa" com um processo aspell
Dentro do código-fonte do pasdoc você pode encontrar duas units que executam 'spell-checking' por uma conversa com o processo aspell em execução através de "pipes":
- A unit PasDoc_ProcessLineTalk.pas implementa a classe TProcessLineTalk, descendente de TProcess, que pode ser facilmente usada para conversar com qualquer processo em uma base de linha-por-linha.
- A unit PasDoc_Aspell.pas implementa a classe TAspellProcess, que executa 'spell-checking' pela utilização de uma instância subjacente TProcessListTalk para executar aspell e comunicar com o processo aspell em execução.
Ambas as units são um pouco independentes do resto dos fontes pasdoc, assim elas pode servir como exemplos reais da utilização de TProcess para executar comunicação através de pipes com outros programas.