Executing External Programs/sk

From Lazarus-ccr

Jump to: navigation, search

Deutsch (de) English (en) Español (es) Français (fr) Japanese (ja) Nederlands (nl) Português (pt) Русский (ru) Slovensky (sk)

Contents

[edit] Úvod

Je mnoho spôsobov ako spustiť externé programy. Zameriame sa na jeden z nich.

[edit] SysUtils.ExecuteProcess

najjednoduchší spôsob, ak nepotrebujete rúry (pipes) alebo žiadne formu ovládania je jednoducho použiť

 
 SysUtils.ExecuteProcess('/full/path/to/binary',['arg1','arg2']);
 

[edit] TProcess

Môžete použiť TProcess na spustenie externých programov. Výhody tohoto spôsobu sú:

  • Nezávislý na platforme
  • Schopnosť čítať zo stdin a stdout.
Poznámka: TProcess nie je terminal/shell! Nemôžete priamo spustiť alebo presmerovať výstup pomocou operátorov ako "|", ">", "<", "&" atď. Možno získať rovnaký výsledok s TProcess pomocou Pascal, príklady nasledujú...

[edit] Jednoduchý príklad

 
 // Toto je ukážkový program ktorý vám ukáže ako
 // spustiť externý program.
 program launchprogram;
 
 // Tu si "použijeme" unity ktoré budeme potrebovať
 uses 
   Classes, SysUtils, Process;
 
 // Toto je definícia premennej APRocess
 // typu "TProcess"
 var 
   AProcess: TProcess;
 
 // Začiatok programu
 begin
   // Vytvoríme objekt TProcess
   // pridelíme ho do premennej AProcess
   AProcess := TProcess.Create(nil);
 
   // Povieme novému procesu aký príkaz má vykonať
   // Použime FPC prekladač
   AProcess.CommandLine := 'ppc386 -h';
 
   // Definujeme nastavenie pre spustenie.
   // Toto nastavenie zaručí že náš program
   // nebude pokračovať až kým sa proces neskončí
   AProcess.Options := AProcess.Options + [poWaitOnExit];
 
   // Teraz keď už proces vie čo má robiť
   // ho môžeme spustiť.
   AProcess.Execute;
 
   // Toto sa dosiahne až po skončení procesu.
   AProcess.Free;   
 end.
 

To je všetko! Práve ste sa naučili ako spustit externý program použitím TProcess.

To je všetko pekné, ale ako získam výstup spusteného programu? Tak sa na to pozrime, trochu rozšírime náš priklad.

[edit] Vylepšený príklad

 
 // Toto je ukážkový program ktorý vám ukáže ako
 // spustiť externý program.
 program launchprogram;
 
 // Tu si "použijeme" unity ktoré budeme potrebovať
 uses 
   Classes, SysUtils, Process;
 
 // Toto je definícia premennej APRocess
 // typu "TProcess"
 // Teraz pridáme aj TStringList aby sme
 // mohli uložiť výstup procesu.
 var 
   AProcess: TProcess;
   AStringList: TStringList;
 
 // Začiatok programu
 begin
   // Vytvoríme objekt TProcess
   // pridelíme ho do premennej AProcess
   AProcess := TProcess.Create(nil);
 
   // Vytvoríme TStringList a pridelíme ho
   AStringList := TStringList.Create;
 
   // Povieme novému procesu aký príkaz má vykonať
   // Použime FPC prekladač
   AProcess.CommandLine := 'ppc386 -h';
 
   // Definujeme nastavenie pre spustenie.
   // Toto nastavenie zaručí že náš program
   // nebude pokračovať až kým sa proces neskončí
   // Zároveň ho nastavíme tak, aby sme mohli
   // čítať výstup.
   AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
 
   // Teraz keď už proces vie čo má robiť
   // ho môžeme spustiť.
   AProcess.Execute;
 
   // Toto sa dosiahne až po skončení procesu.
 
   // Teraz načítame výstup programu
   // do TStringListu.
   AStringList.LoadFromStream(AProcess.Output);
 
   // Uložíme výstup do súboru
   AStringList.SaveToFile('output.txt');
 
   // Teraz keď je už výstup uložený
   // môžeme uvolniť objekty.
   AStringList.Free;
   AProcess.Free;   
 end.
 

[edit] Čítanie veľkého výstupu

V predchádzajúcom príklade sme čakali na ukončenie programu a potom sme čítali čo mal program zapísané do výstupu. Ale predstavte si, že program zapisuje na výstup veľké množstvo dát, rúra sa plní a volaný program čaká na jej vyprázdnenie (prečítanie). Ale volajúci program z rúry nečíta, pretože čaká na ukončenie volaného programu. Nastalo uviaznutie.

Takže nasledujúci príklad nepoužíva poWaitOnExit, ale číta z výstupu, zatiaľ čo program stále beží. Výstup je uchovávaný v pamäťovom streame, ktorý môže byť neskôr použitý na prečítanie výstupu do TStringList.

 program procoutlarge;
 {
     Copyright (c) 2004 by Marc Weustink
 
     Tento príklad je vytvorený v nádeji, že bude užitočný,
     ale BEZ AKEJKOĽVEK ZÁRUKY; dokonca bez implicitnej záruky 
     MERCHANTABILITY alebo 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
   // Nemôžeme tu použiť poWaitOnExit, lebo nepoznáme 
   // veľkosť výstupu. V Linuxe je veľkosť 
   // výstupnej rúry 2 kB. Ak je výstupných dátviac, 
   // musíme dáta prečítať. To však nie je možné, keďže 
   // sme čakajúci. Takže by tu nastalo uviaznutie.
   //
   // Na buferovanie výstupu použijeme dočasný Memorystream 
 
   M := TMemoryStream.Create;
   BytesRead := 0;
 
   P := TProcess.Create(nil);
   P.CommandLine := 'ppc386 -va bogus.pp';
   P.Options := [poUsePipes];
   WriteLn('-- executing --');
   P.Execute;
   while P.Running do
   begin          
     // overenie, že máme dosť priestoru
     M.SetSize(BytesRead + READ_BYTES);
 
     // skús ho prečítať
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
     if n > 0 
     then begin
       Inc(BytesRead, n);
       Write('.')
     end
     else begin     
       // žiadne dáta, počkať 100 ms
       Sleep(100); 
     end;
   end;
   // čítať poslednú časť
   repeat
     // overenie, že máme dosť priestoru
     M.SetSize(BytesRead + READ_BYTES);
     // skús ho prečítať
     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('-- executed --');
 
   S := TStringList.Create;
   S.LoadFromStream(M);
   WriteLn('-- linecount = ', S.Count, ' --');
   for n := 0 to S.Count - 1 do
   begin
     WriteLn('| ', S[n]);
   end;
   WriteLn('-- end --');
   S.Free;
   P.Free;
   M.Free;
 end.

[edit] Použitie vstupu a výstupu z TProcess

Viz príklad processdemo na Lazarus-CCR SVN.

[edit] Pokyny pre použitie TProcess

Ak vytvárate cez platformný program, môžete zmeniť príkazový riadok v závislosti na OS, pomocou direktív "{$IFDEF}s" a "{$ENDIF}s".

Príklad:

 {...}
   AProcess:TProcess.Create(nil)
   {$IFDEF WIN32}
   AProcess.CommandLine := 'calc.exe'; //Windows Calc
   {$ENDIF}
   {$IFDEF LINUX}
   AProcess.CommandLine := 'kcalc'; //KDE Calc
   {$ENDIF}
   AProcess.Execute; //in alternative, you can use AProcess.Active:=True
 {...}

[edit] Príklad komunikácie s procesom aspell

V zdrojovom kóde pasdoc môžete nájsť dve unity, ktoré vykonávajú kontrolu pravopisu komunikáciou s bežiacim procesom aspell cez rúry:

  • PasDoc_ProcessLineTalk.pas unit implementuje triedu TProcessLineTalk, potomka TProcess, ktorú možno jednoducho použiť na komunikáciu s ktorýmkoľvek procesom na báze riadok-po-riadku.
  • PasDoc_Aspell.pas unit implementuje triedu TAspellProcess, ktorá vykonáva kontrolu pravopisu pomocou základnej inštancie TProcessLineTalk pre spustenie aspell a komunikáciu so spusteným procesom aspell.

Obe jednotky sú vcelku nezávislé od zvyšku zdrojového kódu pasdoc, takže môžu poslúžiť ako príklady skutočného použitia TProcess na spustenie a komunikáciu s inými programmi cez rúry.