Sign in Join
Wiki copytemporary

Executing External Programs/pt: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Executing External Programs/pt

OldNewLine
1+## Introdução
2+
3+Existem várias formas de executar um programa externo, mas eu destacarei apenas uma. TProcess.
4+
5+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).
6+
7+**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!
8+
9+## SysUtils.ExecuteProcess
10+
11+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'\]);
12+
13+## TProcess
14+
15+Você pode usar TProcess para iniciar programas externos. Alguns dos beneficios de usar TProcess:
16+
17+- Plataforma Independente
18+- Capacidade de leitura da saída e escrita da entrada.
19+
20+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..
21+
22+### Um Exemplo Simples
23+
24+``` pascal
25+ // Este é um programa de demonstração que mostra como executar
26+ // um programa externo.
27+
28+ program launchprogram;
29+ // Aqui são incluidos arquivos que terão funções úteis
30+ // e procedures que nós precisamos.
31+ uses
32+ Classes, SysUtils, Process;
33+
34+ // Este ponto é definida a variável "AProcess" como uma variável
35+ // do tipo "TProcess"
36+ var
37+ AProcess: TProcess;
38+
39+ // Aqui é onde o nosso programa inicia a execução
40+ begin
41+ // Agora nós criaremos o objeto TProcess, e
42+ // associamos ele à variável AProcess.
43+ AProcess := TProcess.Create(nil);
44+
45+ // Mostraremos ao novo AProcess qual é o comando para ele executar.
46+ // Vamos usar o Compilador FreePascal
47+ AProcess.CommandLine := 'ppc386 -h';
48+
49+ // Nós definiremos uma opção para onde o programa
50+ // é executado. Esta opção verificará que nosso programa
51+ // não continue enquanto o programa que nós executamos
52+ // não pare de executar. vvvvvvvvvvvvvv
53+ AProcess.Options := AProcess.Options + [poWaitOnExit];
54+
55+ // Agora que AProcess sabe qual é a linha de comando
56+ // nós executaremos ele.
57+ AProcess.Execute;
58+
59+ // Esta parte não é alcançada enquanto ppc386 não parar a execução.
60+ AProcess.Free;
61+ end.
62+```
63+
64+É isso! Você aprendeu razoavelmente como executar um programa externo de dentro do seu próprio programa.
65+
66+### Um Exemplo aperfeiçoado
67+
68+Isso é bom, mas como eu leio a saida de um programa que eu executei?
69+
70+Bom, vamos expandir nosso exemplo um pouco e faremos apenas isso:
71+
72+``` pascal
73+ // Este é um programa que mostra como executar
74+ // um programa externo e ler sua saída.
75+ program launchprogram;
76+
77+ // Aqui são incluidos arquivos que terão funções úteis
78+ // e procedures que nós precisamos.
79+ uses
80+ Classes, SysUtils, Process;
81+
82+ // Neste ponto é definida a variável "AProcess" como uma variável
83+ // do tipo "TProcess"
84+ // Também agora nós adicionamos uma TStringList para armazenar os
85+ // dados lidos da saida do programa.
86+ var
87+ AProcess: TProcess;
88+ AStringList: TStringList;
89+
90+ // Aqui é onde o nosso programa inicia a execução
91+ begin
92+ // Agora nós criaremos o objeto TProcess, e
93+ // associamos ele à variável AProcess.
94+ AProcess := TProcess.Create(nil);
95+
96+ // Cria o objeto TStringList.
97+ AStringList := TStringList.Create;
98+
99+ // Mostraremos ao novo AProcess qual é o comando para ele executar.
100+ // Vamos usar o Compilador FreePascal
101+ AProcess.CommandLine := 'ppc386 -h';
102+
103+ // Nós definiremos uma opção para onde o programa
104+ // é executado. Esta opção verificará que nosso programa
105+ // não continue enquanto o programa que nós executamos
106+ // não pare de executar. Também agora vamos mostrar a ele que
107+ // que nós precisamos ler a saída do arquivo.
108+ AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
109+
110+ // Agora que AProcess sabe qual é a linha de comando
111+ // nós executaremos ele.
112+ AProcess.Execute;
113+
114+ // Esta parte não é alcançada enquanto ppc386 não parar a execução.
115+
116+ // Agora lida a saida do programa nós colocaremos
117+ // ela na TStringList.
118+ AStringList.LoadFromStream(AProcess.Output);
119+
120+ // Salvamos a saida para um arquivo.
121+ AStringList.SaveToFile('output.txt');
122+
123+ // Agora que o arquivo foi salvo nós podemos liberar a
124+ // TStringList e o TProcess.
125+ AStringList.Free;
126+ AProcess.Free;
127+ end.
128+```
129+
130+### Lendo a grande saida
131+
132+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á.
133+
134+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.
135+
136+``` pascal
137+ program procoutlarge;
138+ {
139+ Copyright (c) 2004 by Marc Weustink
140+
141+ This example is creeated in the hope that it will be useful,
142+ but WITHOUT ANY WARRANTY; without even the implied warranty of
143+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
144+ }
145+
146+ uses
147+ Classes, Process, SysUtils;
148+
149+ const
150+ READ_BYTES = 2048;
151+
152+ var
153+ S: TStringList;
154+ M: TMemoryStream;
155+ P: TProcess;
156+ n: LongInt;
157+ BytesRead: LongInt;
158+
159+ begin
160+ // Nós não podemos usar poWaitOnExit aqui visto que nós não
161+ // conhecemos o tamanho da saída. No Linux o tamanho do
162+ // pipe de saida é 2 kB. Se os dados da saída são maiores, nós
163+ // precisamos ler os dados. Isto não é possível visto que nós estamos
164+ // esperando. Deste modo nós recebemos um deadlock aqui.
165+ //
166+ // Uma Memorystream temporária é usada para armazenar a saida
167+
168+ M := TMemoryStream.Create;
169+ BytesRead := 0;
170+
171+ P := TProcess.Create(nil);
172+ P.CommandLine := 'ppc386 -va bogus.pp';
173+ P.Options := [poUsePipes];
174+ WriteLn('-- executando --');
175+ P.Execute;
176+ while P.Running do
177+ begin
178+ // Verifica se temos dependências
179+ M.SetSize(BytesRead + READ_BYTES);
180+
181+ // tenta ler ela
182+ n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
183+ if n > 0
184+ then begin
185+ Inc(BytesRead, n);
186+ Write('.')
187+ end
188+ else begin
189+ // sem dados, espera 100 ms
190+ Sleep(100);
191+ end;
192+ end;
193+ // lê a última parte
194+ repeat
195+ // verifica se temos dependências
196+ M.SetSize(BytesRead + READ_BYTES);
197+ // try reading it
198+ n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
199+ if n > 0
200+ then begin
201+ Inc(BytesRead, n);
202+ Write('.');
203+ end;
204+ until n <= 0;
205+ if BytesRead > 0 then WriteLn;
206+ M.SetSize(BytesRead);
207+ WriteLn('-- executado --');
208+
209+ S := TStringList.Create;
210+ S.LoadFromStream(M);
211+ WriteLn('-- número de linhas = ', S.Count, ' --');
212+ for n := 0 to S.Count - 1 do
213+ begin
214+ WriteLn('| ', S[n]);
215+ end;
216+ WriteLn('-- final --');
217+ S.Free;
218+ P.Free;
219+ M.Free;
220+ end.
221+```
222+
223+### Usando a entrada e saida de um TProcess
224+
225+Veja o exemplo processemo no [Lazarus-CCR SVN](https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/examples/process).
226+
227+### Dicas no uso de TProcess
228+
229+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".
230+
231+Exemplo:
232+
233+``` pascal
234+ {...}
235+ AProcess:TProcess.Create(nil)
236+ {$IFDEF WIN32}
237+ AProcess.CommandLine := 'calc.exe'; //Calculadora do Windows
238+ {$ENDIF}
239+ {$IFDEF LINUX}
240+ AProcess.CommandLine := 'kcalc'; //Calculadora do KDE
241+ {$ENDIF}
242+ AProcess.Execute; //em alternativa, você pode usar AProcess.Active:=True
243+ {...}
244+```
245+
246+### Exemplo de "conversa" com um processo aspell
247+
248+Dentro do código-fonte do [pasdoc](http://pasdoc.sourceforge.net/) você pode encontrar duas units que executam 'spell-checking' por uma conversa com o processo aspell em execução através de "pipes":
249+
250+- [A unit PasDoc_ProcessLineTalk.pas](http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/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.
251+
252+- [A unit PasDoc_Aspell.pas](http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/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.
253+
254+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.
255+
256+---
257+*From the Free Pascal wiki, page "Executing External Programs/pt", as it stood on 2020-02-14 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history