Difference between revisions of "Executing External Programs/pt"
Line 4: | Line 4: | ||
Existem múltiplos caminhos para executar um programa externo, mas eu destacarei apenas um. TProcess. | Existem múltiplos caminhos para executar um programa externo, mas eu destacarei apenas um. TProcess. | ||
+ | |||
+ | Se você sempre usou '''ShellExecute''' e/ou '''WinExec''' em Delphi, então você pode começar a usar TProcess como alternativa em FPC/Lazarus (isto é valido também se você está executando Lazarus em 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! | ||
==TProcess== | ==TProcess== |
Revision as of 22:57, 16 April 2006
│
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 múltiplos caminhos para executar um programa externo, mas eu destacarei apenas um. TProcess.
Se você sempre usou ShellExecute e/ou WinExec em Delphi, então você pode começar a usar TProcess como alternativa em FPC/Lazarus (isto é valido também se você está executando Lazarus em 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!
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.
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 acontece.
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(memory stream), 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.
Example of "talking" with aspell process
Inside pasdoc source code you can find two units that perform spell-checking by "talking" with running aspell process through pipes:
- PasDoc_ProcessLineTalk.pas unit implements TProcessLineTalk class, descendant of TProcess, that can be easily used to talk with any process on a line-by-line basis.
- PasDoc_Aspell.pas units implements TAspellProcess class, that performs spell-checking by using underlying TProcessLineTalk instance to execute aspell and communicate with running aspell process.
Both units are rather independent from the rest of pasdoc sources, so they may serve as real-world examples of using TProcess to run and communicate through pipes with other program.