Sign in Join
Wiki copytemporary

Executing External Programs/pl: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11Wykonywanie programów zewnętrznych
22
33## Przegląd: Porównanie
44
55Istnieją różne sposoby dostępne w bibliotekach RTL, FCL i LCL dotyczące wykonywania zewnętrznego polecenia/procesu/programu.
66
77| Metoda | Biblioteka | Platformy | Pojedyncza linia | Cechy |
88|----|----|----|----|----|
99| [[Executing External Programs/pl|ExecuteProcess]] | RTL | Wieloplatformowy | Tak | Bardzo ograniczone, synchroniczne. |
1010| [[Executing External Programs/pl|ShellExecute]] | WinAPI | Tylko MS Windows | Tak | Wiele. Może uruchamiać programy z podwyższonymi uprawnieniami administratora. |
1111| [[Executing External Programs/pl|fpsystem, fpexecve]] | Unix | Tylko Unix | | |
1212| [[Executing External Programs/pl|TProcess]] | FCL | Wieloplatformowy | Nie | Pełny. |
1313| [[Executing External Programs/pl|RunCommand]] | FCL | Wieloplatformowy **Wymaga FPC 2.6.2+** | Tak | Obejmuje typowe użycie TProcess. |
1414| [[Executing External Programs/pl|OpenDocument]] | LCL | Wieloplatformowy | Tak | Tylko otwarty dokument. Dokument otworzy się z aplikacją powiązaną z podanym typem dokumentu. |
1515
1616## (Proces.)RunCommand
1717
1818- Odnośnik do [RunCommand](http://www.freepascal.org/docs-html/fcl/process/runcommand.html)
1919- Odnośnik do [RunCommandInDir](http://www.freepascal.org/docs-html/fcl/process/runcommandindir.html)
2020
2121W FPC 2.6.2 niektóre funkcje pomocnicze dla TProcess zostały dodane do modułu process w oparciu o wrappery (funkcje lub klasy opakowujące) używane w projekcie [[Projects using Lazarus|fpcup]]. Te funkcje są przeznaczone do użytku podstawowego i pośredniego, i mogą przechwytywać dane wyjściowe do pojedynczego ciągu string i w pełni obsługiwać duże dane wyjściowe.
2222
2323Prosty przykład to:
2424
2525``` pascal
2626program project1;
2727
2828{$mode objfpc}{$H+}
2929
3030uses
3131 Process;
3232
3333var
3434 s : ansistring;
3535
3636begin
3737
3838if RunCommand('/bin/bash',['-c','echo $PATH'],s) then
3939 writeln(s);
4040
4141end.
4242```
4343
4444Zauważ jednak, że nie wszystkie „wbudowane” polecenia powłoki (np. aliasy) działają, ponieważ aliasy domyślnie nie są rozwijane w powłokach nieinteraktywnych, a .bashrc nie jest odczytywany przez powłoki nieinteraktywne, chyba że ustawisz zmienną środowiskową BASH_ENV. tak więc poniższy przykąłd nie daje żadnych danych wyjściowych:
4545
4646``` pascal
4747program project2;
4848
4949{$mode objfpc}{$H+}
5050
5151uses
5252 Process;
5353
5454var
5555 s : ansistring;
5656
5757begin
5858
5959if RunCommand('/bin/bash',['-c','alias'],s) then
6060 writeln(s);
6161
6262end.
6363```
6464
6565Przeciążony wariant RunCommand zwraca kod wyjścia programu. RunCommandInDir uruchamia polecenie w innym katalogu (ustawia p.CurrentDirectory):
6666
6767``` pascal
6868function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;var outputstring:string; var exitstatus:integer): integer;
6969function RunCommandIndir(const curdir:string;const exename:string;const commands:array of string;var outputstring:string): boolean;
7070function RunCommand(const exename:string;const commands:array of string;var outputstring:string): boolean;
7171```
7272
7373W **FPC 3.2.0+** RunCommand otrzymał dodatkowe warianty, które pozwalają nadpisać TProcessOptions i WindowOptions.
7474
7575### Rozszerzenia RunCommand
7676
7777W **FPC 3.2.0+** implementacja RunCommand została uogólniona i ponownie zintegrowana z TProcess, aby umożliwić szybszą budowę własnych wariantów. Jako przykład wariant RunCommand z limitem czasu:
7878
7979``` pascal
8080
8181{$mode delphi}
8282uses classes, sysutils, process, dateutils;
8383type
8484 { TProcessTimeout }
8585 TProcessTimeout = class(TProcess)
8686 public
8787 timeoutperiod: TTime;
8888 timedout : boolean;
8989 started : TDateTime;
9090 procedure LocalnIdleSleep(Sender,Context : TObject;status:TRunCommandEventCode;const message:string);
9191 end;
9292
9393procedure TProcessTimeout.LocalnIdleSleep(Sender,Context : TObject;status:TRunCommandEventCode;const message:string);
9494begin
9595 if status=RunCommandIdle then
9696 begin
9797 if (now-started)>timeoutperiod then
9898 begin
9999 timedout:=true;
100100 Terminate(255);
101101 exit;
102102 end;
103103 sleep(RunCommandSleepTime);
104104 end;
105105end;
106106
107107function RunCommandTimeout(const exename:TProcessString;const commands:array of TProcessString;out outputstring:string; Options : TProcessOptions = [];SWOptions:TShowWindowOptions=swoNone;timeout:integer=60):boolean;
108108Var
109109 p : TProcessTimeout;
110110 i,
111111 exitstatus : integer;
112112 ErrorString : String;
113113begin
114114 p:=TProcessTimeout.create(nil);
115115 p.OnRunCommandEvent:=p.LocalnIdleSleep;
116116 p.timeoutperiod:=timeout/SecsPerDay;
117117 if Options<>[] then
118118 P.Options:=Options - [poRunSuspended,poWaitOnExit];
119119 p.options:=p.options+[poRunIdle]; // potrzebne do uruchomienia zdarzenia RUNIDLE. Zobacz Zmiany Użytkownika dla wersji 3.2.0
120120
121121 P.ShowWindow:=SwOptions;
122122 p.Executable:=exename;
123123 if high(commands)>=0 then
124124 for i:=low(commands) to high(commands) do
125125 p.Parameters.add(commands[i]);
126126 p.timedout:=false;
127127 p.started:=now;
128128 try
129129 // główna pętla wariantów runcommand(), pierwotnie oparta na scenariuszu "dużego wyjścia" na wiki, ale stale rozwijana przez 5 lat.
130130 result:=p.RunCommandLoop(outputstring,errorstring,exitstatus)=0;
131131 if p.timedout then
132132 result:=false;
133133 finally
134134 p.free;
135135 end;
136136 if exitstatus<>0 then result:=false;
137137end;
138138
139139// przykładowe zastosowanie:
140140
141141var
142142 s : string;
143143begin
144144 for s in FileList do
145145 begin
146146 if not RunCommandTimeout('someexe',['-v',s,'--output','dest\'+s],err,[],swoNone,60) then
147147 begin
148148 // nie udało się uruchomić lub upłynął limit czasu. np. movefile() do "wadliwego" katalogu.
149149 end
150150 else
151151 begin
152152 // ok, plik przeniesiony do "dobrego" katalogu.
153153 end;
154154 end;
155155end;
156156```
157157
158158## SysUtils.ExecuteProcess
159159
160160(Wieloplatformowy)\
161161Pomimo wielu ograniczeń, najprostszym sposobem uruchomienia programu (modalnego, bez potoków lub jakiejkolwiek formy sterowania) jest po prostu użycie:
162162
163163``` pascal
164164SysUtils.ExecuteProcess(UTF8ToSys('/full/path/to/binary'), '', []);
165165```
166166
167167Proces wywołujący działa synchronicznie: „zawiesza się” do momentu zakończenia działania zewnętrznego programu — ale może to być przydatne, jeśli wymagasz od użytkownika wykonania czegoś przed kontynuowaniem pracy w aplikacji. Aby uzyskać bardziej wszechstronne podejście, zapoznaj się z sekcją dotyczącą preferowanego międzyplatformowego **RunCommand** lub innej funkcjonalności **TProcess**, lub jeśli chcesz obsługiwać tylko system Windows, możesz użyć **ShellExecute**.
168168
169169- Odniesienie do [ExecuteProcess](http://www.freepascal.org/docs-html/rtl/sysutils/executeprocess.html)
170170
171171## MS Windows: CreateProcess, ShellExecute i WinExec
172172
173173> **Note:** Chociaż FPC/Lazarus obsługuje **CreateProcess**, **ShellExecute** i/lub **WinExec**, ta obsługa jest dostępna tylko w Win32/64. Jeśli Twój program jest wieloplatformowy, rozważ użycie **RunCommand** lub **TProcess**.
174174
175175> **Note:** WinExec to 16-bitowe wywołanie, które od lat jest przestarzałe w interfejsie API systemu Windows. W ostatnich wersjach FPC generuje ostrzeżenie.
176176
177177**ShellExecute** to standardowa funkcja systemu MS Windows (ShellApi.h) z dobrą \[<http://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85>).aspx dokumentacją na MSDN\] (zwróć uwagę na ich komentarze na temat inicjalizacji COM, jeśli odkryjesz, że ta jest niewiarygodna).
178178
179179``` pascal
180180uses ..., ShellApi;
181181
182182// Proste jednowierszowe (ignorowanie zwracanych błędów):
183183if ShellExecute(0,nil, PChar('"C:\my dir\prog.exe"'),PChar('"C:\somepath\some_doc.ext"'),nil,1) =0 then;
184184
185185// Wykonaj plik wsadowy:
186186if ShellExecute(0,nil, PChar('cmd'),PChar('/c mybatch.bat'),nil,1) =0 then;
187187
188188// Otwórz okno poleceń w danym folderze:
189189if ShellExecute(0,nil, PChar('cmd'),PChar('/k cd \path'),nil,1) =0 then;
190190
191191// Otwórz adres URL strony internetowej w domyślnej przeglądarce za pomocą polecenia „start” (poprzez ukryte okno cmd):
192192if ShellExecute(0,nil, PChar('cmd'),PChar('/c start www.lazarus.freepascal.org/'),nil,0) =0 then;
193193
194194// lub przydatna procedura:
195195procedure RunShellExecute(const prog,params:string);
196196begin
197197 // parametry: ( Uchwyt, nil/'open'/'edit'/'find'/'explore'/'print', // 'open' nie zawsze jest potrzebny
198198 // path+prog, parametry, folder roboczy,
199199 // okno command 0=ukryte / 1=SW_SHOWNORMAL / 3=maks / 7=min) // dla stałych SW_ : uses ... Windows ...
200200 if ShellExecute(0,'open',PChar(prog),PChar(params),PChar(extractfilepath(prog)),1) >32 then; //sukces
201201 // zwracane wartości 0..32 są błędami
202202end;
203203```
204204
205205Istnieje również ShellExecuteExW jako wersja WideChar, a ShellExecuteExA to wersja AnsiChar.
206206
207207Opcja fMask może również używać SEE_MASK_DOENVSUBST lub SEE_MASK_FLAG_NO_UI lub SEE_MASK_NOCLOSEPROCESS itp.
208208
209209Jeśli w Delphi używałeś ShellExecute do **dokumentów** takich jak dokumenty Word lub adresy URL, spójrz na funkcje open* (OpenURL itp.) w module lclintf (zobacz sekcję [Zobacz także](https://wiki.lazarus.freepascal.org/Executing_External_Programs/pl#Zobacz_także) na dole tej strony).
210210
211211### Używanie ShellExecuteEx do podnoszenia uprawnień administratora
212212
213213Jeśli potrzebujesz uruchomić zewnętrzny program z podwyższonymi uprawnieniami administratora, możesz użyć metody **runas** z alternatywną funkcją ShellExecuteEx:
214214
215215``` pascal
216216uses ShellApi, ...;
217217
218218function RunAsAdmin(const Handle: Hwnd; const Path, Params: string): Boolean;
219219var
220220 sei: TShellExecuteInfoA;
221221begin
222222 FillChar(sei, SizeOf(sei), 0);
223223 sei.cbSize := SizeOf(sei);
224224 sei.Wnd := Handle;
225225 sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
226226 sei.lpVerb := 'runas';
227227 sei.lpFile := PAnsiChar(Path);
228228 sei.lpParameters := PAnsiChar(Params);
229229 sei.nShow := SW_SHOWNORMAL;
230230 Result := ShellExecuteExA(@sei);
231231end;
232232
233233procedure TFormMain.RunAddOrRemoveApplication;
234234begin
235235 // Przykład, który używa podwyższonego uprawnienia dla rundll, aby otworzyć Panel sterowania do programów i funkcji
236236 RunAsAdmin(FormMain.Handle, 'rundll32.exe shell32.dll,Control_RunDLL appwiz.cpl', '');
237237end;
238238```
239239
240240## Unix fpsystem, fpexecve i shell
241241
242242Te funkcje są zależne od platformy.
243243
244244- Odniesienie do [fpsystem](http://www.freepascal.org/docs-html/rtl/unix/fpsystem.html)
245245- Odniesienie do [fpexecve](http://www.freepascal.org/docs-html/rtl/baseunix/fpexecve.html)
246246
247247Linux.Shell/Unix.Shell był odpowiednikiem fpsystem w wersji 1.0.x ze słabo zdefiniowaną obsługą błędów i po dekadzie deprecjacji został ostatecznie usunięty. Prawie we wszystkich przypadkach może być zastąpiony przez fpsystem, który obsługuje więcej standardów POSIX, takich jak obsługa błędów.
248248
249249## TProcess
250250
251251Możesz użyć TProcess do uruchamiania zewnętrznych programów. Niektóre z korzyści płynących z używania TProcess to:
252252
253253- Jest niezależny od platformy.
254254- Potrafi czytać ze standardowego wyjścia i zapisywać na standardowe wejście.
255255- Możliwe jest oczekiwanie na zakończenie polecenia lub pozwolenie na jego działanie podczas działania programu.
256256
257257Ważne informacje:
258258
259259- TProcess nie jest terminalem/powłoką! Nie możesz bezpośrednio wykonywać skryptów lub przekierowywać wyjścia za pomocą operatorów takich jak „\|”, „\>”, „\<”, „&” itp. Możliwe jest uzyskanie tych samych wyników za pomocą TProcess i za pomocą pascala - kilka przykładów poniżej.
260260- Przypuszczalnie w systemie Linux/Unix: **musisz** podać pełną ścieżkę do pliku wykonywalnego. Na przykład „/bin/cp” zamiast „cp”. Jeśli program znajduje się w standardowej PATH, możesz użyć funkcji [[doc:lcl/fileutil/finddefaultexecutablepath.html|FindDefaultExecutablePath]] z modułu [[doc:lcl/fileutil/index.html|FileUtil]] biblioteki LCL.
261261- W systemie Windows, jeśli polecenie znajduje się w ścieżce, nie musisz określać pełnej ścieżki.
262262- Odnośnik do [[doc:fcl/process/tprocess.html|TProcess]]
263263
264264### Najprostszy przykład
265265
266266Wiele typowych przypadków zostało przygotowanych w funkcjach [[Executing External Programs/pl|RunCommand]]. Zanim zaczniesz kopiować i wklejać poniższe przykłady, najpierw je sprawdź.
267267
268268### Prosty przykład
269269
270270Ten przykład (**który nie powinien być używany w środowisku produkcyjnym, patrz [[Executing External Programs/pl|Czytanie dużych ilości danych wyjściowych]] lub, lepiej, [[Executing External Programs/pl|RunCommand]]**) pokazuje tylko, jak uruchomić zewnętrzny program, nic więcej:
271271
272272``` pascal
273273// Jest to program demonstracyjny, który
274274// pokazuje, jak uruchomić zewnętrzny program.
275275program launchprogram;
276276
277277// Tutaj dołączamy moduły zawierające przydatne
278278// funkcje i procedury, których będziemy potrzebować.
279279uses
280280 Classes, SysUtils, Process;
281281
282282// Definiuje zmienną "AProcess" jako zmienną typu "TProcess"
283283var
284284 AProcess: TProcess;
285285
286286// Tu zaczyna działać nasz program
287287begin
288288 // Teraz utworzymy obiekt TProcess i przypiszemy go
289289 // do zmiennej AProcess.
290290 AProcess := TProcess.Create(nil);
291291
292292 // Powiedz nowemu AProcess, jakie jest polecenie do wykonania.
293293 // Użyjmy kompilatora Free Pascal (dokładniej wersji x64)
294294 // Lecz jeśli używasz kompilatora 32-bit zmień ppcx64 na ppc386
295295 AProcess.Executable:= 'ppcx64';
296296
297297 // Przekaż opcję -h razem z ppcx64, więc faktycznie wykonywane
298298 // jest polecenie 'ppcx64 -h':
299299 AProcess.Parameters.Add('-h');
300300
301301 // Zdefiniujemy opcję działającą, w czasie wykonywania programu.
302302 // Ta opcja sprawi, że nasz program nie będzie kontynuowany,
303303 // dopóki program zewnętrzy, który uruchomimy, nie przestanie działać.
304304 // /------------\
305305 AProcess.Options := AProcess.Options + [poWaitOnExit];
306306
307307 // Teraz pozwól AProcess uruchomić program zewnętrzny
308308 AProcess.Execute;
309309
310310 // Poniższy kod nie wykona się, dopóki ppcx64 nie przestanie działać.
311311 AProcess.Free;
312312end.
313313```
314314
315315Otóż ​​to! Właśnie nauczyłeś się uruchamiać zewnętrzny program z wnętrza własnego programu.
316316
317317### Ulepszony przykład (ale jeszcze niepoprawny)
318318
319319Wszystko fajnie, ale jak odczytać dane wyjściowe uruchomionego programu?
320320
321321Cóż, rozszerzmy nieco nasz przykład, jak poniżej: **Ten przykład jest prosty, więc możesz się z niego uczyć. Jednak nie używaj tego przykładu w kodzie produkcyjnym, ale użyj kodu z [[Executing External Programs/pl|Czytanie dużych ilości danych wyjściowych]].**
322322
323323``` pascal
324324// To jest
325325// WADLIWY
326326// program demonstracyjny, który pokazuje,
327327// jak uruchomić zewnętrzny program
328328// i odczytać z jego dane wyjściowe.
329329program launchprogram;
330330
331331// Tutaj dołączamy moduły zawierające przydatne
332332// funkcje i procedury, których będziemy potrzebować.
333333uses
334334 Classes, SysUtils, Process;
335335
336336// Definiuje zmienną "AProcess" jako zmienną typu "TProcess"
337337// Teraz także dodajemy TStringList do przechowywania danych
338338// odczytanych z wyjścia programu.
339339var
340340 AProcess: TProcess;
341341 AStringList: TStringList;
342342
343343// Tu zaczyna działać nasz program
344344begin
345345 // Teraz utworzymy obiekt TProcess i przypiszemy go
346346 // do zmiennej AProcess.
347347 AProcess := TProcess.Create(nil);
348348
349349 // Powiedz nowemu AProcess, jakie jest polecenie do wykonania.
350350 AProcess.Executable := '/usr/bin/ppcx64';
351351 AProcess.Parameters.Add('-h');
352352
353353 // Zdefiniujemy opcję działającą, w czasie wykonywania programu.
354354 // Ta opcja sprawi, że nasz program nie będzie kontynuowany,
355355 // dopóki program zewnętrzy, który uruchomimy, nie przestanie działać.
356356 // Dodatkowo teraz powiemy mu, że chcemy odczytać dane wyjściowe.
357357 // /------------|-----------\
358358 AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
359359
360360 // Teraz, gdy AProcess wie, jaki jest wiersz poleceń, można go uruchomić.
361361 AProcess.Execute;
362362
363363 // Po zakończeniu AProcess zostanie wykonana reszta programu.
364364
365365 // Teraz odczytaj wynik działania programu, za pomocą TStringList.
366366 AStringList := TStringList.Create;
367367 AStringList.LoadFromStream(AProcess.Output);
368368
369369 // Zapisz dane wyjściowe do pliku i zwolnij obiekt AStringList.
370370 AStringList.SaveToFile('output.txt');
371371 AStringList.Free;
372372
373373 // Teraz, gdy dane wyjściowe z procesu są przetworzone, także można je zwolnić.
374374 AProcess.Free;
375375end.
376376```
377377
378378### Czytanie dużych ilości danych wyjściowych
379379
380380W poprzednim przykładzie czekaliśmy, aż program się zakończy. Następnie czytaliśmy, co program zapisał na swoim wyjściu.
381381
382382Załóżmy, że program zapisuje dużo danych na wyjściu. Następnie potok wyjściowy zapełnia się i wywoływany program czeka, aż potok zostanie odczytany.
383383
384384Ale program wywołujący nie czyta z niego, dopóki wywoływany program się nie zakończy. Następuje impas.
385385
386386Poniższy przykład nie używa zatem poWaitOnExit, ale odczytuje dane wyjściowe, gdy program jest nadal uruchomiony. Dane wyjściowe są przechowywane w strumieniu pamięci, który można później wykorzystać do odczytania danych wyjściowych do TStringList.
387387
388388Jeśli chcesz odczytać dane wyjściowe z procesu zewnętrznego i nie możesz użyć RunCommand, jest to kod, który powinien być podstawą do użytku produkcyjnego. Jeśli używasz **FPC 3.2.0+**, parametryzowalna forma tej pętli jest dostępna jako metoda **RunCommandLoop** w TProcess. Zdarzenie **OnRunCommandEvent** można podłączyć, aby dalej modyfikować zachowanie.
389389
390390``` pascal
391391program LargeOutputDemo;
392392
393393{$mode objfpc}{$H+}
394394
395395uses
396396 Classes, SysUtils, Process; // Process to moduł, który zawiera TProcess
397397
398398const
399399 BUF_SIZE = 2048; // Rozmiar bufora do odczytu danych wyjściowych w porcjach
400400
401401var
402402 AProcess : TProcess;
403403 OutputStream : TStream;
404404 BytesRead : longint;
405405 Buffer : array[1..BUF_SIZE] of byte;
406406
407407begin
408408 // Skonfiguruj proces; jako przykład używane jest rekurencyjne przeszukiwanie
409409 // katalogów, ponieważ zwykle skutkuje to dużą ilością danych.
410410 AProcess := TProcess.Create(nil);
411411
412412 // Polecenia dla Windows i *nix są różne, stąd dyrektywy $IFDEF
413413 {$IFDEF Windows}
414414 // W systemie Windows polecenie dir nie może być użyte bezpośrednio, ponieważ jest to
415415 // wbudowane polecenie powłoki. Dlatego potrzebny jest cmd.exe i dodatkowe parametry.
416416 AProcess.Executable := 'c:\windows\system32\cmd.exe';
417417 AProcess.Parameters.Add('/c');
418418 AProcess.Parameters.Add('dir /s c:\windows');
419419 {$ENDIF Windows}
420420
421421 {$IFDEF Unix}
422422 AProcess.Executable := '/bin/ls';
423423
424424 {$IFDEF Darwin}
425425 AProcess.Parameters.Add('-recursive');
426426 AProcess.Parameters.Add('-all');
427427 {$ENDIF Darwin}
428428
429429 {$IFDEF Linux}
430430 AProcess.Parameters.Add('--recursive');
431431 AProcess.Parameters.Add('--all');
432432 {$ENDIF Linux}
433433
434434 {$IFDEF FreeBSD}
435435 AProcess.Parameters.Add('-R');
436436 AProcess.Parameters.Add('-a');
437437 {$ENDIF FreeBSD}
438438
439439 AProcess.Parameters.Add('-l');
440440 {$ENDIF Unix}
441441
442442 // Aby można było przechwycić dane wyjściowe, należy użyć opcji procesu poUsePipes.
443443 // Nie można użyć opcji procesu poWaitOnExit, ponieważ zablokuje to program główny,
444444 // uniemożliwiając mu odczytanie danych wyjściowych procesu zewnętrznego.
445445 AProcess.Options := [poUsePipes];
446446
447447 // Uruchom proces (uruchom polecenie dir dla Windows lub ls dla Linux/Unix)
448448 AProcess.Execute;
449449
450450 // Utwórz obiekt strumienia, w którym będą przechowywane wygenerowane dane wyjściowe.
451451 // Może to być również strumień plikowy do bezpośredniego zapisywania danych wyjściowych na dysku.
452452 OutputStream := TMemoryStream.Create;
453453
454454 // Wszystkie wygenerowane dane wyjściowe z AProcess są odczytywane w pętli,
455455 // dopóki nie będzie dostępnych więcej danych
456456 repeat
457457 // Pobierz nowe dane z procesu do maksymalnego rozmiaru buforu, który został przydzielony.
458458 // Zauważ, że wszystkie wywołania Read(...) będą blokowane z wyjątkiem ostatniego, które zwraca 0 (zero).
459459 BytesRead := AProcess.Output.Read(Buffer, BUF_SIZE);
460460
461461 // Bajty, które zostały odczytane, dodaj do strumienia w celu późniejszego wykorzystania
462462 OutputStream.Write(Buffer, BytesRead)
463463
464464 until BytesRead = 0; // Zakończ pętlę, jeśli nie ma więcej danych
465465
466466 // Proces się zakończył, więc można go posprzątać
467467 AProcess.Free;
468468
469469 // Teraz, gdy wszystkie dane zostały odczytane, można z nich korzystać;
470470 // na przykład po to, by zapisać je do pliku na dysku
471471 with TFileStream.Create('output.txt', fmCreate) do
472472 begin
473473 OutputStream.Position := 0; // Wymagane, aby upewnić się, że wszystkie dane będą kopiowane od początku
474474 CopyFrom(OutputStream, OutputStream.Size);
475475 Free
476476 end;
477477
478478 // Lub dane mogą być wyświetlane na ekranie
479479 with TStringList.Create do
480480 begin
481481 OutputStream.Position := 0; // Wymagane, aby upewnić się, że wszystkie dane będą kopiowane od początku
482482 LoadFromStream(OutputStream);
483483 writeln(Text);
484484 writeln('--- Liczba linii = ', Count, '----');
485485 Free
486486 end;
487487
488488 // Sprzątanie
489489 OutputStream.Free;
490490end.
491491```
492492
493493Zauważ, że powyższe można również osiągnąć za pomocą RunCommand:
494494
495495``` pascal
496496var s: string;
497497...
498498RunCommand('c:\windows\system32\cmd.exe', ['/c', 'dir /s c:\windows'], s);
499499```
500500
501501### Korzystanie z wejścia i wyjścia TProcess
502502
503503Zobacz przykładowe demo procesu w [Lazarus-CCR SVN](https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/examples/process).
504504
505505### Wskazówki dotyczące korzystania z TProcess
506506
507507Podczas tworzenia programu wieloplatformowego nazwę pliku wykonywalnego specyficzną dla systemu operacyjnego można ustawić za pomocą dyrektyw „{\$IFDEF}” i „{\$ENDIF}”. Przykład:
508508
509509``` pascal
510510{...}
511511AProcess := TProcess.Create(nil)
512512
513513{$IFDEF WIN32}
514514 AProcess.Executable := 'calc.exe';
515515{$ENDIF}
516516
517517{$IFDEF LINUX}
518518 AProcess.Executable := FindDefaultExecutablePath('kcalc');
519519{$ENDIF}
520520
521521AProcess.Execute;
522522{...}
523523```
524524
525525### macOS pokazuje pakiet aplikacji na pierwszym planie
526526
527527Możesz uruchomić **pakiet aplikacji** przez TProcess, uruchamiając plik wykonywalny w pakiecie. Na przykład:
528528
529529``` pascal
530530 AProcess.Executable:='/Applications/iCal.app/Contents/MacOS/iCal';
531531```
532532
533533Spowoduje to uruchomienie *Kalendarza*, ale okno będzie znajdować się za bieżącą aplikacją. Aby uzyskać aplikację na pierwszym planie, możesz użyć narzędzia **open** z parametrem **-n**:
534534
535535``` pascal
536536 AProcess.Executable:='/usr/bin/open';
537537 AProcess.Parameters.Add('-n');
538538 AProcess.Parameters.Add('-a'); // opcjonalny: określa aplikację do użycia; przeszukuje tylko katalogi aplikacji
539539 AProcess.Parameters.Add('-W'); // opcjonalnie: open czeka, aż aplikacje, które otwiera (lub były już otwarte) zostaną zamknięte
540540 AProcess.Parameters.Add('Pages.app'); // dołączenie .app jest opcjonalne
541541```
542542
543543Jeśli Twoja aplikacja potrzebuje parametrów, możesz przekazać wraz z **open** parametr **--args**, po którym wszystkie dalsze parametry są przekazywane do aplikacji:
544544
545545``` pascal
546546 AProcess.Parameters.Add('--args');
547547 AProcess.Parameters.Add('argument1');
548548 AProcess.Parameters.Add('argument2');
549549```
550550
551551Zobacz także: [[macOS Open Sesame|macOS polecenie open]].
552552
553553### Uruchom oddzielny program
554554
555555Normalnie program uruchomiony przez twoją aplikację jest procesem potomnym i zostaje zabity, gdy twoja aplikacja zostanie zabita. Jeśli chcesz uruchomić samodzielny program, który nadal będzie działał, możesz użyć:
556556
557557``` pascal
558558var
559559 Process: TProcess;
560560 I: Integer;
561561begin
562562 Process := TProcess.Create(nil);
563563 try
564564 Process.InheritHandles := False;
565565 Process.Options := [];
566566 Process.ShowWindow := swoShow;
567567
568568 // Skopiuj domyślne zmienne środowiskowe, w tym zmienną DISPLAY, aby aplikacja GUI działała
569569 for I := 1 to GetEnvironmentVariableCount do
570570 Process.Environment.Add(GetEnvironmentString(I));
571571
572572 Process.Executable := '/usr/bin/gedit';
573573 Process.Execute;
574574 finally
575575 Process.Free;
576576 end;
577577end;
578578```
579579
580580### Przykład „rozmowy” z procesem aspell
581581
582582Wewnątrz kodu źródłowego [pasdoc](https://github.com/pasdoc/pasdoc/wiki) można znaleźć dwa moduły, które sprawdzają pisownię poprzez „rozmawianie” przez potoki z uruchomionym procesem aspell:
583583
584584- [Moduł PasDoc_ProcessLineTalk.pas](https://github.com/pasdoc/pasdoc/blob/master/source/component/PasDoc_ProcessLineTalk.pas) implementuje klasę TProcessLineTalk, potomka TProcess, która może być z łatwością używana do komunikacji z dowolnym procesem linia po linii.
585585
586586- [Moduł PasDoc_Aspell.pas](https://github.com/pasdoc/pasdoc/blob/master/source/component/PasDoc_Aspell.pas) implementuje klasę TAspellProcess, która sprawdza pisownię za pomocą bazowej instancji TProcessLineTalk do wykonania aspell i komunikacji z uruchomionym procesem aspell.
587587
588588Obydwa moduły są raczej niezależne od pozostałych źródeł pasdoc, więc mogą służyć jako rzeczywiste przykłady użycia TProcess do uruchamiania i komunikacji przez potoki z innym programem.
589589
590590### Zastępowanie operatorów powłoki, takich jak „\| \< \>”
591591
592592Czasami chcesz uruchomić bardziej skomplikowane polecenie, które przesyła dane do innego polecenia lub do pliku. Coś podobnego do
593593
594594``` pascal
595595ShellExecute('firstcommand.exe | secondcommand.exe');
596596```
597597
598598lub
599599
600600``` pascal
601601ShellExecute('dir > output.txt');
602602```
603603
604604Wykonanie tego za pomocą TProcess nie zadziała. tj:
605605
606606``` pascal
607607// to nie zadziała!
608608Process.CommandLine := 'firstcommand.exe | secondcommand.exe';
609609Process.Execute;
610610```
611611
612612#### Dlaczego używanie specjalnych operatorów do przekierowywania wyjścia nie działa?
613613
614614TProcess nie jest środowiskiem powłoki, tylko procesem. To nie dwa procesy, to tylko jeden. Możliwe jest jednak przekierowanie danych wyjściowych dokładnie tak, jak chcesz. Zobacz [[Executing External Programs/pl|następną sekcję]].
615615
616616### Jak przekierować wyjście za pomocą TProcess
617617
618618Możesz przekierować dane wyjściowe polecenia do innego polecenia, używając osobnej instancji TProcess dla **każdego** polecenia.
619619
620620Oto przykład, który wyjaśnia, jak przekierować dane wyjściowe jednego procesu do drugiego. Aby przekierować wyjście procesu do pliku/strumienia, zobacz przykład [[Executing External Programs/pl|Czytanie dużych ilości danych wyjściowych]].
621621
622622Możesz nie tylko przekierować „normalne” wyjście (znane również jako stdout), ale możesz także przekierować wyjście błędu (stderr), jeśli określisz opcję poStderrToOutPut, jak to widać w opcjach drugiego procesu.
623623
624624``` pascal
625625program Project1;
626626
627627uses
628628 Classes, sysutils, process;
629629
630630var
631631 FirstProcess,
632632 SecondProcess: TProcess;
633633 Buffer: array[0..127] of char;
634634 ReadCount: Integer;
635635 ReadSize: Integer;
636636begin
637637 FirstProcess := TProcess.Create(nil);
638638 SecondProcess := TProcess.Create(nil);
639639
640640 FirstProcess.Options := [poUsePipes];
641641 FirstProcess.Executable := 'pwd';
642642
643643 SecondProcess.Options := [poUsePipes,poStderrToOutPut];
644644 SecondProcess.Executable := 'grep';
645645 SecondProcess.Parameters.Add(DirectorySeparator+ ' -');
646646 // byłoby to to samo co "pwd | grep / -"
647647
648648 FirstProcess.Execute;
649649 SecondProcess.Execute;
650650
651651 while FirstProcess.Running or (FirstProcess.Output.NumBytesAvailable > 0) do
652652 begin
653653 if FirstProcess.Output.NumBytesAvailable > 0 then
654654 begin
655655 // upewnij się, że nie czytamy więcej danych niż przydzieliliśmy w buforze
656656 ReadSize := FirstProcess.Output.NumBytesAvailable;
657657 if ReadSize > SizeOf(Buffer) then
658658 ReadSize := SizeOf(Buffer);
659659 // teraz wczytaj dane wyjściowe do bufora
660660 ReadCount := FirstProcess.Output.Read(Buffer[0], ReadSize);
661661 // i zapisz bufor do drugiego procesu
662662 SecondProcess.Input.Write(Buffer[0], ReadCount);
663663
664664 // jeśli SecondProcess zapisuje dużo danych do swojego wyjścia,
665665 // powinniśmy odczytać te dane tutaj, aby zapobiec zakleszczeniu,
666666 // patrz poprzedni przykład "Czytanie dużych ilości danych wyjściowych"
667667 end;
668668 end;
669669 // Zamknij dane wejściowe w SecondProcess,
670670 // aby zakończyć przetwarzanie swoich danych
671671 SecondProcess.CloseInput;
672672
673673 // i poczekaj, aż się zakończy, lecz uważaj, jakie polecenie uruchamiasz,
674674 // ponieważ może się ono nie zakończyć, gdy jego dane wejściowe są zamknięte,
675675 // to następująca linia może zapętlić się w nieskończoność
676676 while SecondProcess.Running do
677677 Sleep(1);
678678 // Gotowe! Reszta programu jest tylko po to, aby przykład był bardziej 'użyteczny'
679679
680680 // użyjemy ponownie Buffer, aby wyprowadzić wyjście SecondProcess do *tego* programu stdout
681681 WriteLn('Rozpoczęcie wyjścia grep:');
682682 ReadSize := SecondProcess.Output.NumBytesAvailable;
683683 if ReadSize > SizeOf(Buffer) then
684684 ReadSize := SizeOf(Buffer);
685685 if ReadSize > 0 then
686686 begin
687687 ReadCount := SecondProcess.Output.Read(Buffer, ReadSize);
688688 WriteLn(Copy(Buffer,0, ReadCount));
689689 end
690690 else
691691 WriteLn('grep nie znalazł tego, czego szukaliśmy. ', SecondProcess.ExitStatus);
692692 WriteLn('Zakończenie wyjścia grep:');
693693
694694 // zwolnij obiekty naszych procesów
695695 FirstProcess.Free;
696696 SecondProcess.Free;
697697end.
698698```
699699
700700W ten sposób możesz przekierować dane wyjściowe z jednego programu do drugiego.
701701
702702#### Uwagi
703703
704704Ten przykład może wydawać się przesadny, ponieważ możliwe jest uruchamianie „skomplikowanych” poleceń przy użyciu powłoki przy pomocy TProcess, takich jak:
705705
706706``` pascal
707707Process.Commandline := 'sh -c "pwd | grep / -"';
708708```
709709
710710Ale nasz przykład jest bardziej wieloplatformowy, ponieważ nie wymaga modyfikacji, aby działać w systemie Windows lub Linux itp. Polecenie „sh” może, ale nie musi istnieć na twojej platformie i jest ogólnie dostępny tylko na platformach *nix. W naszym przykładzie mamy również większą elastyczność, ponieważ możesz czytać i zapisywać z/do wejścia, wyjścia i stderr każdego procesu z osobna, co może być bardzo korzystne dla twojego projektu.
711711
712712### Przekierowywanie wejścia i wyjścia oraz działanie z rootem
713713
714714Częstym problemem w systemach Unix (FreeBSD, macOS) i Linux jest to, że chcesz uruchomić jakiś program na koncie root (lub, bardziej ogólnie, na innym koncie użytkownika). Przykładem może być uruchomienie polecenia *ping*.
715715
716716Jeśli możesz użyć do tego sudo, możesz dostosować następujący przykład zaadaptowany z postu opublikowanego przez andymana na forum ([1](http://lazarus.freepascal.org/index.php/topic,14479.0.html)). Ten przykład uruchamia polecenie `ls` w katalogu `/root`, ale oczywiście można go dostosować.
717717
718718**Lepszym sposobem** na to jest użycie pakietu policykit, który powinien być dostępny we wszystkich najnowszych Linuksach. [Zobacz wątek na forum, aby uzyskać szczegółowe informacje.](http://lazarus.freepascal.org/index.php/topic,14479.0.html)
719719
720720Duże części tego kodu są podobne do wcześniejszego przykładu, ale pokazuje również, jak przekierować stdout i stderr procesu wywoływanego oddzielnie na stdout i stderr naszego własnego kodu.
721721
722722``` pascal
723723program rootls;
724724
725725{ Demonstracja użycia TProcess, przekierowania stdout/stderr do naszego stdout/stderr,
726726 wywoływania sudo w systemach FreeBSD/Linux/macOS i dostarczania danych wejściowych na stdin}
727727{$mode objfpc}{$H+}
728728
729729uses
730730 Classes,
731731 Math, {for min}
732732 Process;
733733
734734 procedure RunsLsRoot;
735735 var
736736 Proc: TProcess;
737737 CharBuffer: array [0..511] of char;
738738 ReadCount: integer;
739739 ExitCode: integer;
740740 SudoPassword: string;
741741 begin
742742 WriteLn('Please enter the sudo password:');
743743 Readln(SudoPassword);
744744 ExitCode := -1; //Zacznij od porażki, zobaczmy później, czy to zadziała
745745 Proc := TProcess.Create(nil); //Utwórz nowy proces
746746 try
747747 Proc.Options := [poUsePipes, poStderrToOutPut]; //Użyj potoków, aby przekierować stdin,stdout,stderr
748748 Proc.CommandLine := 'sudo -S ls /root'; //Uruchom ls /root jako root za pomocą sudo
749749 // -S powoduje, że sudo odczytuje hasło z stdin.
750750 Proc.Execute; //Uruchom to. sudo prawdopodobnie poprosi teraz o hasło
751751
752752 // wpisz hasło do stdin programu sudo:
753753 SudoPassword := SudoPassword + LineEnding;
754754 Proc.Input.Write(SudoPassword[1], Length(SudoPassword));
755755 SudoPassword := '%*'; // krótki string, mam nadzieję, że trochę pomiesza pamięć; uwaga: używanie PChars jest bardziej niezawodne
756756 SudoPassword := ''; // i sprawić, by program był nieco bezpieczniejszy przed węszeniem?!?
757757
758758 // główna pętla do odczytu wyjścia z stdout i stderr dla sudo
759759 while Proc.Running or (Proc.Output.NumBytesAvailable > 0) or
760760 (Proc.Stderr.NumBytesAvailable > 0) do
761761 begin
762762 // odczytaj stdout i zapisz do naszego stdout
763763 while Proc.Output.NumBytesAvailable > 0 do
764764 begin
765765 ReadCount := Min(512, Proc.Output.NumBytesAvailable); //Czytaj do bufora, nie więcej
766766 Proc.Output.Read(CharBuffer, ReadCount);
767767 Write(StdOut, Copy(CharBuffer, 0, ReadCount));
768768 end;
769769 // odczytaj stderr i zapisz do naszego stderr
770770 while Proc.Stderr.NumBytesAvailable > 0 do
771771 begin
772772 ReadCount := Min(512, Proc.Stderr.NumBytesAvailable); //Czytaj do bufora, nie więcej
773773 Proc.Stderr.Read(CharBuffer, ReadCount);
774774 Write(StdErr, Copy(CharBuffer, 0, ReadCount));
775775 end;
776776 end;
777777 ExitCode := Proc.ExitStatus;
778778 finally
779779 Proc.Free;
780780 Halt(ExitCode);
781781 end;
782782 end;
783783
784784begin
785785 RunsLsRoot;
786786end.
787787```
788788
789789Inne przemyślenia: Bez wątpienia wskazane byłoby sprawdzenie, czy sudo rzeczywiście pyta o hasło. Można to konsekwentnie sprawdzać, ustawiając zmienną środowiskową SUDO_PROMPT na coś, na co zwracamy uwagę podczas czytania stdout TProcess, unikając problemu związanego z różnymi znakami zachęty dla różnych lokalizacji. Ustawienie zmiennej środowiskowej powoduje wyczyszczenie wartości domyślnych (odziedziczonych z naszego procesu), więc w razie potrzeby musimy skopiować środowisko z naszego programu.
790790
791791### Używanie fdisk z sudo w systemie Linux
792792
793793Poniższy przykład pokazuje, jak uruchomić fdisk na komputerze z systemem Linux za pomocą polecenia sudo, aby uzyskać uprawnienia roota. **Uwaga: jest to tylko przykład i nie obejmuje dużej ilości danych na wyjściu.**
794794
795795``` pascal
796796program getpartitioninfo;
797797{Pierwotnie napisany przez użytkownika forum Lazarus wjackon153. Prosimy o kontakt w przypadku pytań, uwag itp.
798798Zmodyfikowan z fragmentu kodu Lazarusa na program FPC dla ułatwienia zrozumienia/zwięzłości przez BigChimp}
799799
800800Uses
801801 Classes, SysUtils, FileUtil, Process;
802802
803803var
804804 hprocess: TProcess;
805805 sPass: String;
806806 OutputLines: TStringList;
807807
808808begin
809809 sPass := 'yoursudopasswordhere'; // Musisz to zmienić na własne hasło sudo
810810 OutputLines:=TStringList.Create; //dla pewności warto zamknąć to w bloku try...finally...end
811811 // OutputLines został utworzony ... To samo dla hProcess.
812812
813813 // Poniższy przykład otworzy fdisk w tle i da nam informacje o partycjach
814814 // Ponieważ fdisk wymaga podwyższonych uprawnień, musimy przekazać
815815 // nasze hasło jako parametr do sudo za pomocą opcji -S, więc proces
816816 // poczeka, aż nasz program wyśle ​​nasze hasło do aplikacji sudo
817817
818818 hProcess := TProcess.Create(nil);
819819 // W systemach Linux/Unix/FreeBSD/macOS musimy podać pełną ścieżkę do naszego pliku wykonywalnego:
820820 hProcess.Executable := '/bin/sh';
821821 // Teraz dodajemy wszystkie parametry w wierszu poleceń:
822822 hprocess.Parameters.Add('-c');
823823 // Tutaj przesyłamy potokiem hasło do polecenia sudo, które następnie wykonuje fdisk -l:
824824 hprocess.Parameters.add('echo ' + sPass + ' | sudo -S fdisk -l');
825825 // Uruchom asynchronicznie (poczekaj na zakończenie procesu) i użyj potoków, abyśmy mogli odczytać potok wyjściowy
826826 hProcess.Options := hProcess.Options + [poWaitOnExit, poUsePipes];
827827 // Teraz wykonaj:
828828 hProcess.Execute;
829829
830830 // hProcess powinien teraz uruchomić zewnętrzny plik wykonywalny (ponieważ używamy poWaitOnExit).
831831 // Teraz możesz przetworzyć wyjście procesu (standardowe wyjście i standardowy błąd), np.:
832832 OutputLines.Add('stdout:');
833833 OutputLines.LoadFromStream(hprocess.Output);
834834 OutputLines.Add('stderr:');
835835 OutputLines.LoadFromStream(hProcess.Stderr);
836836 // Pokaż dane wyjściowe na ekranie:
837837 writeln(OutputLines.Text);
838838
839839 // Wyczyść, aby uniknąć wycieków pamięci:
840840 hProcess.Free;
841841 OutputLines.Free;
842842
843843 //Poniżej znajduje się kilka przykładów, jak widać, możemy przekazywać niedozwolone znaki, tak jak robimy to z terminala
844844 //Nawet jeśli przeczytałeś gdzie indziej, że nie możesz upewnić się tą metodą, to możesz :)
845845
846846 //hprocess.Parameters.Add('ping -c 1 www.google.com');
847847 //hprocess.Parameters.Add('ifconfig wlan0 | grep ' + QuotedStr('inet addr:') + ' | cut -d: -f2');
848848
849849 //Użycie QuotedStr() nie jest wymagane, chociaż zapewnia czystszy kod;
850850 //możesz użyć podwójnego cudzysłowu i mieć ten sam efekt.
851851
852852 //hprocess.Parameters.Add('glxinfo | grep direct');
853853
854854 // Ta metoda może być również używana do instalowania aplikacji z repozytorium:
855855
856856 //hprocess.Parameters.add('echo ' + sPass + ' | sudo -S apt-get install -y pkg-name');
857857
858858 end.
859859```
860860
861861### Parametry zawierające spacje (Zastępowanie cudzysłowów powłoki)
862862
863863W powłoce Linuksa możliwe jest pisanie cytowanych argumentów w następujący sposób:
864864
865-`gdb --batch --eval-command="info symbol 0x0000DDDD" myprogram`
865+```text
866+gdb --batch --eval-command="info symbol 0x0000DDDD" myprogram
867+```
866868
867869Polecenie GDB otrzyma 3 argumenty (oprócz pierwszego argumentu, który jest pełną ścieżką do pliku wykonywalnego):
868870
8698711. --batch
8708722. --eval-command=info symbol 0x0000DDDD
8718733. pełna ścieżka do myprogram
872874
873875Najlepszym rozwiązaniem, aby uniknąć skomplikowanego cytowania, jest przejście na TProcess.Parameters.Add zamiast ustawiania wiersza poleceń dla nietrywialnych przypadków, np.
874876
875-` AProcess.Executable:='/usr/bin/gdb';`\
876-` AProcess.Parameters.Add('--batch');`\
877-` AProcess.Parameters.Add('--eval-command=info symbol 0x0000DDDD'); // zwróć tutaj uwagę na brak cytowania`\
878-` AProcess.Parameters.Add('/home/me/myprogram');`
877+``` pascal
878+ AProcess.Executable:='/usr/bin/gdb';
879+ AProcess.Parameters.Add('--batch');
880+ AProcess.Parameters.Add('--eval-command=info symbol 0x0000DDDD'); // zwróć tutaj uwagę na brak cytowania
881+ AProcess.Parameters.Add('/home/me/myprogram');
882+```
879883
880884Pamiętaj też, aby używać tylko pełne ścieżki.
881885
882886TProcess.Commandline obsługuje jednak tylko podstawowe cytowanie parametrów z cudzysłowami. Ujmij w apostrofy *cały* parametr zawierający spacje z podwójnymi cudzysłowami. Jak poniżej:
883887
884-`AProcess.CommandLine := '/usr/bin/gdb --batch "--eval-command=info symbol 0x0000DDDD" /home/me/myprogram';`
888+``` pascal
889+AProcess.CommandLine := '/usr/bin/gdb --batch "--eval-command=info symbol 0x0000DDDD" /home/me/myprogram';
890+```
885891
886892Właściwość .CommandLine jest [przestarzała](http://bugs.freepascal.org/view.php?id=14446), a raporty o błędach do obsługi bardziej skomplikowanych przypadków cytowania nie będą akceptowane.
887893
888894## Alternatywy LCLIntf
889895
890896Czasami nie trzeba jawnie wywoływać zewnętrznego programu, aby uzyskać potrzebną funkcjonalność. Zamiast otwierać aplikację i określać dokument, który ma być z nią powiązany, po prostu poproś system operacyjny o otwarcie dokumentu i pozwól mu użyć domyślnej aplikacji powiązanej z tym typem pliku. Poniżej kilka przykładów.
891897
892898### Otwieranie dokumentu w domyślnej aplikacji
893899
894900W niektórych sytuacjach musisz otworzyć jakiś dokument/plik przy użyciu domyślnej aplikacji z nim powiązanej, zamiast uruchamiać konkretny program. To zależy od działającego systemu operacyjnego. Lazarus zapewnia niezależną od platformy procedurę OpenDocument, która zajmie się tym za Ciebie. Twoja aplikacja będzie nadal działać, nie czekając na zamknięcie procesu tworzenia dokumentu.
895901
896902``` pascal
897903uses LCLIntf;
898904...
899905OpenDocument('manual.pdf');
900906...
901907```
902908
903909- [[opendocument|Dokumentacja OpenDocument]]
904910
905911### Otwieranie strony web w domyślnej przeglądarce internetowej
906912
907913Aby to zrobić, po prostu przekaż wymagany adres URL. Przedrostek protokołu <http://> wydaje się w pewnych okolicznościach opcjonalny. Ponadto przekazanie nazwy pliku wydaje się dawać takie same wyniki jak OpenDocument()
908914
909915``` pascal
910916uses LCLIntf;
911917...
912918OpenURL('www.lazarus.freepascal.org/');
913919```
914920
915921Zobacz także:
916922
917923- [[OpenURL|Odnośnik do OpenURL]]
918924
919925Lub możesz użyć **TProcess** w taki sposób:
920926
921927``` pascal
922928uses Process;
923929
924930procedure OpenWebPage(URL: string);
925931// Możliwe, że musisz podać swój adres URL w cudzysłowiu np. "www.lazarus.freepascal.org"
926932var
927933 Browser, Params: string;
928934begin
929935 FindDefaultBrowser(Browser, Params);
930936 with TProcess.Create(nil) do
931937 try
932938 Executable := Browser;
933939 Params:=Format(Params, [URL]);
934940 Params:=copy(Params,2,length(Params)-2); // usuń znaki "", nowa wersja TProcess.Parameters robi to sama
935941 Parameters.Add(Params);
936942 Options := [poNoConsole];
937943 Execute;
938944 finally
939945 Free;
940946 end;
941947end;
942948```
943949
944950## Zobacz także
945951
946952- [dokumentacja TProcess](http://lazarus-ccr.sourceforge.net/docs/fcl/process/tprocess.html)
947953- [[opendocument|OpenDocument]]
948954- [[OpenURL]]
949955- [[TProcessUTF8]]
950956- [[TXMLPropStorage]]
951957- [[Webbrowser]]
952958
953959---
954960*From the Free Pascal wiki, page "Executing External Programs/pl", as it stood on 2023-11-03 after a change by Slawek, 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