Sign in Join
Wiki copytemporary

Executing External Programs/es: what changed

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

OldNewLine
11## Introducción
22
33   Hay varias formas de ejecutar programas externos, pero nos centraremos en una, **TProcess**.
44
55Si en Delphi utilizabas siempre **ShellExecute** y/o **WinExec**, puedes empezar a usar TProcess como alternativa en FPC/Lazarus (es válido también si estás ejecutando Lazarus en Linux, porque TProcess es multiplataforma).
66
77   **Nota:** FPC/Lazarus puede utilizar **ShellExecute** y/o **WinExec**, pero sólo en Win32. Si tu programa está enfocado a varias plataformas, utiliza TProcess, ¡es mejor!.
88
99Aquí tenemos las diferentes maneras disponibles sobre como ejecutar un programa/proceso/mandato externo en RTL, FCL y LCL.
1010
1111| Metodo | Librería | Plataformas | Línea simple | Características |
1212|----|----|----|----|----|
1313| [[Executing External Programs|ExecuteProcess]] | RTL | Plataforma Cruzada | Si | Muy limitado, synchronous |
1414| [[Executing External Programs|ShellExecute]] | WinAPI | MS Windows only | Yes | Muchos. Permite iniciar programas con permisos de elevación/admin. |
1515| [[Executing External Programs|fpsystem, fpexecve]] | Unix | Unix solamente | | |
1616| [[Executing External Programs/es|TProcess]] | FCL | Plataforma cruzada | No | Completas |
1717| [[Executing External Programs|RunCommand]] | FCL | Plataforma cruzada, **Requiere FPC 2.6.2+** | Si | Cubre el uso común de TProcess |
1818| [[Executing External Programs|OpenDocument]] | LCL | Plataforma cruzada | si | Solo para abrir documentos. El documento debe abrirse con la aplicación asociada al tipo de documento. |
1919
2020## TProcess
2121
2222   Puedes utilizar TProcess para ejecutar programas externos. Algunas de sus ventajas son:
2323
2424- Independiente de la plataforma
2525- Capaz de leer desde la entrada estándar (*stdout*) y de escribir en la salida estándar (*stdin*).
2626
2727   **Nota**: TProcess no es un terminal de shell! No puedes ejecutar directamente secuencias de comandos o reorientar la salida usando operadores como "\|", "\>", "\<", "&", etc. Es posible obtener los mismos resultados con TProcess utilizando Pascal, mira algunos ejemplos más abajo..
2828
2929   **Importante**: Debes especificar la ruta completa al ejecutable. Por ejemplo "/bin/cp " en lugar de "cp". Si el programa está en la ruta estándar, puedes utilizar la función **FindDefaultExecutablePath** de la unidad **FileUtil** de la LCL.
3030
3131### Un ejemplo sencillo
3232
3333``` pascal
3434 // Este es un programa de demostración que enseña como lanzar
3535 // un programa externo.
3636 program lanzarprograma;
3737
3838 uses
3939 Classes, SysUtils, Process;
4040
4141 // Definición de "UnProceso" como una variable
4242 // de tipo "TProcess"
4343 var
4444 UnProceso: TProcess;
4545
4646 begin
4747 // Ahora creamos UnProceso.
4848 UnProceso := TProcess.Create(nil);
4949
5050 // Asignamos a UnProceso la orden que debe ejecutar.
5151 // Vamos a lanzar el compilador de FreePascal
5252 UnProceso.CommandLine := 'ppc386 -h';
5353
5454 // Definimos una opción de comportamiento de 'TProccess'
5555 // La opción poWaitOnExit hará que nuestro programa
5656 // se detenga hasta que termine el programa lanzado
5757 UnProceso.Options := UnProceso.Options + [poWaitOnExit];
5858
5959 // Lanzamos la ejecución de 'ppc386 -h'.
6060 UnProceso.Execute;
6161
6262 // Nuestro programa espera hasta que 'ppc386' finaliza.
6363 UnProceso.Free;
6464 end.
6565```
6666
6767   ¡Eso es todo! Acabas de aprender cómo se ejecuta un programa externo desde dentro de tu propio programa.
6868
6969### Un ejemplo mejorado
7070
7171   De acuerdo, pero ¿cómo leo la salida que produce un programa que he ejecutado?
7272
7373   Bien, vamos a ampliar un poco nuestro ejemplo mediante lo siguiente:
7474
7575``` pascal
7676 program lanzarprograma2;
7777
7878 uses
7979 Classes, SysUtils, Process;
8080
8181 // Definición de "UnProceso" como una variable de tipo "TProcess"
8282 // También añadimos un TStringList para almacenar los datos
8383 // leídos desde la salida del programa.
8484 var
8585 UnProceso: TProcess;
8686 UnaLista: TStringList;
8787
8888 // Aquí comienza a ejecutarse nuestro programa.
8989 begin
9090
9191 // Creamos el objeto TStringList.
9292 UnaLista := TStringList.Create;
9393
9494 // Ahora creamos UnProceso.
9595 UnProceso := TProcess.Create(nil);
9696
9797 // Asignamos a UnProceso la orden que debe ejecutar.
9898 // Vamos a lanzazar el compilador de FreePascal
9999 // (CommandLine está Obsoleto)
100100 UnProceso.CommandLine := 'ppc386 -h';
101101
102102 // Definimos una opción de comportamiento de 'TProccess'
103103 // La opción poWaitOnExit hará que nuestro programa
104104 // se detenga hasta que termine el programa lanzado
105105 // con la opción poUsePipes advertimos que vamos a utilizar tuberías de Entrada/Salida
106106 // para que se capture la salida y así poder recuperar su contenido desde nuestro programa
107107
108108 UnProceso.Options := UnProceso.Options + [poWaitOnExit, poUsePipes];
109109
110110 // Lanzamos la ejecución de 'ppc386 -h'.
111111 UnProceso.Execute;
112112
113113 // Nuestro programa se detiene hasta que 'ppc386' finaliza.
114114
115115 // Ahora leemos la salida del programa que acabamos de ejecutar
116116 // dentro de TStringList.
117117 UnaLista.LoadFromStream(UnProceso.Output);
118118
119119 // Guardamos la salida en un archivo.
120120 UnaLista.SaveToFile('salida.txt');
121121
122122 // Ahora que hemos guardado el archivo podemos liberar la memoria
123123 // TStringList y TProcess.
124124 UnaLista.Free;
125125 UnProceso.Free;
126126 end.
127127```
128128
129129### Lectura de muchos datos de salida
130130
131131   En el ejemplo anterior esperamos a que el programa termine. En ese momento leemos lo que el programa ha escrito en la salida. Pero si el programa escribe muchos datos, la tubería se llena y será necesario leerlos para vaciarla, pero el programa llamante no leerá hasta que el programa llamado haya terminado. Nos encontraremos ante un típico *bloqueo de la muerte*.
132132
133133   El siguiente ejemplo, por tanto, no utiliza poWaitOnExit, sino que va leyendo la salida mientras el programa llamado se está ejecutando. La salida se almacena en una memoria intermedia, que se utilizará más tarde para leer en un TStringList, por ejemplo.
134134
135135``` pascal
136136 program procoutlarge;
137137 { Copyright (c) 2004 by Marc Weustink
138138
139139 Este ejemplo se ha creado con la esperanza de que resulte útil,
140140 pero SIN NINGUNA GARANTÍA; ni tan siquiera la garantía implícita de
141141 COMERCIALIZACIÓN o ADECUACIÓN A UN OBJETIVO PARTICULAR.
142142 }
143143
144144 uses
145145 Classes, Process, SysUtils;
146146
147147 const
148148 READ_BYTES = 2048;
149149
150150 var
151151 S: TStringList;
152152 M: TMemoryStream;
153153 P: TProcess;
154154 n: LongInt;
155155 BytesRead: LongInt;
156156
157157 begin
158158 // No podemos utilizar poWaitOnExit porque no
159159 // conocemos el tamaño de la salida. En Linux el tamaño
160160 // de la salida de la tubería es de 2 kB. Si los datos de salida son más
161161 // necesitamos leerlos. Esto no es posible, ya que estamos
162162 // esperando. Así que aquí nos encontramos en un punto muerto.
163163 //
164164 // Se utiliza un Memorystream temporal para almacenar la salida
165165
166166 M := TMemoryStream.Create;
167167 BytesRead := 0;
168168
169169 P := TProcess.Create(nil);
170170 P.CommandLine := 'ppc386 -va bogus.pp';
171171 P.Options := [poUsePipes];
172172 WriteLn('-- ejecutando --');
173173 P.Execute;
174174 while P.Running do
175175 begin
176176 // nos aseguramos de tener espacio
177177 M.SetSize(BytesRead + READ_BYTES);
178178
179179 // intentamos leerlo
180180 n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
181181 if n > 0
182182 then begin
183183 Inc(BytesRead, n);
184184 Write('.')
185185 end
186186 else begin
187187 // sin datos, esperamos 100 milisegundos
188188 Sleep(100);
189189 end;
190190 end;
191191 // leemos la última parte
192192 repeat
193193 // nos aseguramos de tener espacio
194194 M.SetSize(BytesRead + READ_BYTES);
195195 // intentamos leerlo
196196 n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
197197 if n > 0
198198 then begin
199199 Inc(BytesRead, n);
200200 Write('.');
201201 end;
202202 until n <= 0;
203203 if BytesRead > 0 then WriteLn;
204204 M.SetSize(BytesRead);
205205 WriteLn('-- ejecutado --');
206206
207207 S := TStringList.Create;
208208 S.LoadFromStream(M);
209209 WriteLn('-- total de líneas = ', S.Count, ' --');
210210 for n := 0 to S.Count - 1 do
211211 begin
212212 WriteLn('| ', S[n]);
213213 end;
214214 WriteLn('-- fin --');
215215 S.Free;
216216 P.Free;
217217 M.Free;
218218 end.
219219```
220220
221221### Uso de entrada y salida de un TProcess
222222
223223   Véase el ejemplo processdemo en [Lazarus-CCR SVN](https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/examples/process)
224224
225225### Notas sobre la utilización de TProcess
226226
227227   Si estas creando un programa que funciones en diversas plataformas, puedes cambiar el programa a ejecutar de acuerdo con el sistema operativo, mediante las directivas *{\$IFDEF}* y *{\$ENDIF}*.
228228
229229   Ejemplo:
230230
231231``` pascal
232232 {...}
233233 unProceso:TProcess.Create(nil)
234234 {$IFDEF WIN32}
235235 unProceso.CommandLine := 'calc.exe'; //calculadora de Windows
236236 {$ENDIF}
237237 {$IFDEF LINUX}
238238 unProceso.CommandLine := 'kcalc'; //calculadora de KDE o bien xcalc si no tienes KDE
239239 {$ENDIF}
240240 unProceso.Execute; //también puedes utilizar unProceso.Active:=True
241241 {...}
242242```
243243
244244En cuanto a TProcess tomando como referencia las propiedades del componente visual tiene las siguientes opciones (po=process options):
245245
246246- poDebugOnlyThisProcess.
247247- poDebugProcess.
248248- poDefaultErrorMode
249249- poNewConsole.
250250- poNewProcessGroup.
251251- poNoConsole.
252252- poRunSuspended.
253253- poStderrToOutPut.
254254- poUsePipes: utilizado para interconectar procesos.
255255- poWaitOnExit: esperar a que finalice el programa.
256256
257257![](/wiki-images/6/6e/TProcess_Options.PNG)
258258
259259A falta de explicar que hace cada opción.
260260
261261[Referencia TProcess](http://lazarus-ccr.sourceforge.net/docs/fcl/process/tprocess.html).
262262
263263### Ejemplo de *conversación* con el proceso aspell
264264
265265   Dentro del código fuente [pasdoc](http://pasdoc.sourceforge.net/) puedes encontrar dos unidades que realizan corrección ortográfica *conversando* con un proceso aspell a través de tuberías:
266266
267267- [PasDoc_ProcessLineTalk.pas unit](http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_ProcessLineTalk.pas) ejecuta la clase TProcessLineTalk, descendiente de TProcess, que se puede utilizar fácilmente para comunicar con cualquier proceso línea a línea.
268268
269269- [PasDoc_Aspell.pas units](http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_Aspell.pas) ejecuta la clase TAspellProcess, que realiza corrección ortográfica utilizando la instancia fundamental TProcessLineTalk para ejecutar aspell y comunicarse con el proceso aspell que se está ejecutando.
270270
271271   Ambas unidades son bastante independientes del resto de fuentes de pasdoc, así que pueden servir como ejemplos reales de la utilización de TProcess para ejecutar y comunicarse a través de tuberías con otros programas.
272272
273273### Reemplazar operadores de *Shell* como "\|", "\<" y "\>"
274274
275275   A veces queremos ejecutar una orden compleja que envía (entuba) sus datos a otra orden o a un archivo. Algo como
276276
277-` ShellExecute('primeraorden.exe | segundaorden.exe');`
277+```text
278+ ShellExecute('primeraorden.exe | segundaorden.exe');
279+```
278280
279281o
280282
281-` ShellExecute('dir > salida.txt');`
283+```text
284+ ShellExecute('dir > salida.txt');
285+```
282286
283287    Esto no funciona con TProcess. p.e.:
284288
285-` // esto no funciona`\
286-` Process.CommandLine := 'primeraorden.exe | segundaorden.exe'; `\
287-` Process.Execute;`
289+``` pascal
290+ // esto no funciona
291+ Process.CommandLine := 'primeraorden.exe | segundaorden.exe';
292+ Process.Execute;
293+```
288294
289295#### ¿Por qué utilizar operadores especiales para redirigir la salida no funciona?
290296
291297   TProcess es justamente, eso, un proceso, no es un entorno de *shell*. No es dos procesos, únicamente es un proceso. Es posible, no obstante, redirigir la salida de la manera que queremos. Ver [[Executing External Programs/es|más adelante, la siguiente sección]].
292298
293299### Cómo redirigir la salida con TProcess
294300
295301   Podemos redirigir la salidad de un comando a otro comando utilizando una instancia de TProcess para cada commando.
296302
297303   Este es un ejemplo que explica cómo redirigir la salida de un proceso a otro. Para redirigir la salida de un proceso a un archivo o flujo ver el ejemplo [[Executing External Programs/es|Lectura de muchos datos de salida]]
298304
299305``` pascal
300306 program Proyecto1;
301307
302308 uses
303309 Classes, sysutils, process;
304310
305311 var
306312 PrimerProceso,
307313 SegundoProceso: TProcess;
308314 Buffer: array[0..127] of char;
309315 ContadorLectura: Integer;
310316 TamanyoLectura: Integer;
311317 begin
312318 PrimerProceso := TProcess.Create(nil);
313319 SegundoProceso := TProcess.Create(nil);
314320
315321 PrimerProceso.Options := [poUsePipes];
316322 SegundoProceso.Options := [poUsePipes,poStderrToOutPut];
317323
318324 PrimerProceso.CommandLine := 'pwd';
319325 SegundoProceso.CommandLine := 'grep '+ DirectorySeparator+ ' -';
320326 // esto sería lo mismo que "pwd | grep / -"
321327
322328 PrimerProceso.Execute;
323329 SegundoProceso.Execute;
324330
325331 while PrimerProceso.Running or (PrimerProceso.Output.NumBytesAvailable > 0) do
326332 begin
327333 if PrimerProceso.Output.NumBytesAvailable > 0 then
328334 begin
329335 // asegurate de que no lees más datos que los asignados
330336 // en el buffer
331337 TamanyoLectura := PrimerProceso.Output.NumBytesAvailable;
332338 if TamanyoLectura > SizeOf(Buffer) then
333339 TamanyoLectura := SizeOf(Buffer);
334340 // ahora leemos la salida en el buffer
335341 ContadorLectura := PrimerProceso.Output.Read(Buffer[0], TamanyoLectura);
336342 // y escribimos el buffer en el segundo proceso
337343 SegundoProceso.Input.Write(Buffer[0], ContadorLectura);
338344
339345 // Si SegundoProceso escribe muchos datos en la salida a continuación,
340346 // debes leer los datos aquí para evitar un punto muerto
341347 // ver el ejemplo anterior "Lectura de muchos datos de salida"
342348 end;
343349 end;
344350 // Cerrar la entrad de SegundoProceso
345351 // y finaliza el procesamiento de datos
346352 SegundoProceso.CloseInput;
347353
348354 // y esperar a que finalice
349355 // ten cuidado con que comando se ejecuta porque no puede terminar cuando
350356 // la entrada está cerrada y la siguiente línea será un bucle sin fin
351357 while SegundoProceso.Running do
352358 Sleep(1);
353359 // ¡eso es todo! el resto del programa es sólo un ejemplo
354360 // es poco "útil"
355361
356362 // vamos a reutilizar el buffer para la salida del SegundoProceso
357363 // a la salida estándar de este programa
358364 WriteLn('Comienza la salida de Grep:');
359365 TamanyoLectura := SegundoProceso.Output.NumBytesAvailable;
360366 if TamanyoLectura > SizeOf(Buffer) then
361367 TamanyoLectura := SizeOf(Buffer);
362368 if TamanyoLectura > 0 then
363369 begin
364370 ContadorLectura := SegundoProceso.Output.Read(Buffer, TamanyoLectura);
365371 WriteLn(Copy(Buffer,0, ContadorLectura));
366372 end
367373 else
368374 WriteLn('grep NO encontró lo que se buscaba. ', SegundoProceso.ExitStatus);
369375 WriteLn('Termina la salida de Grep:');
370376
371377 // Liberamos los objetos TProcess
372378 PrimerProceso.Free;
373379 SegundoProceso.Free;
374380 end.
375381```
376382
377383   Eso es todo. Ahora podemos redirigir la salida de un programa a otro.
378384
379385#### Notas
380386
381387   Este ejemplo puede parecer exagerado, ya que es posible ejecutar "complicados" comandos shell con TProcess como:
382388
383-` Process.Commandline := 'sh -c "pwd | grep / -"';`
389+``` pascal
390+ Process.Commandline := 'sh -c "pwd | grep / -"';
391+```
384392
385393   Pero el ejemplo es más multiplataforma, ya que no necesita ninguna modificación para ejecutarse en Windows o Linux, etc. *sh* puede o no existir en su plataforma y, en general sólo disponible en plataformas *nix. También tenemos más flexibilidad en nuestro ejemplo ya que se puede leer y escribir desde/a la entrada, salida y salida de error estándar de cada proceso individual, lo que podría ser muy ventajoso para tu proyecto.
386394
387395### Redirigir entrada y salida bajo *root*
388396
389397   Un problema común en Unix (macOS) y Linux surge cuando se desea ejecutar algún programa en la cuenta de *root* (o, en otra cuenta de usuario). Un ejemplo sería ejecutar el comando ping''''.
390398
391399   Si puedes usar sudo para esto, se puede adaptar el ejemplo siguiente, una adaptación de uno publicado por andyman en el foro ([1](http://lazarus.freepascal.org/index.php/topic,14479.0.html)). Este ejemplo ejecuta la orden `ls` en el `/root`, pero por supuesto puede ser adaptada.
392400
393401   "Una forma mejor'' de hacerlo es usar el paquete PolicyKit, que debería estar disponible en todos los Linux recientes. [ver el hilo del foro para más detalles.](http://lazarus.freepascal.org/index.php/topic,14479.0.html)
394402
395403   Gran parte de este código es similar al ejemplo anterior, pero también se muestra cómo redirigir los flujos stdout y stderr del proceso llamado a los flujos stdout y stderr de nuestro propio código.
396404
397405``` pascal
398406 program rootls;
399407
400408 { Demonstrates using TProcess, redirecting stdout/stderr to our stdout/stderr,
401409 calling sudo on Linux/macOS, and supplying input on stdin}
402410 {$mode objfpc}{$H+}
403411
404412 uses
405413 Classes,
406414 Math, {for min}
407415 Process;
408416
409417 procedure RunsLsRoot;
410418 var
411419 Proc: TProcess;
412420 CharBuffer: array [0..511] of char;
413421 ReadCount: integer;
414422 ExitCode: integer;
415423 SudoPassword: string;
416424 begin
417425 WriteLn('Please enter the sudo password:');
418426 Readln(SudoPassword);
419427 ExitCode := -1; //Start out with failure, let's see later if it works
420428 Proc := TProcess.Create(nil); //Create a new process
421429 try
422430 Proc.Options := [poUsePipes, poStderrToOutPut]; //Use pipes to redirect program stdin,stdout,stderr
423431 Proc.CommandLine := 'sudo -S ls /root'; //Run ls /root as root using sudo
424432 // -S causes sudo to read the password from stdin.
425433 Proc.Execute; //start it. sudo will now probably ask for a password
426434
427435 // write the password to stdin of the sudo program:
428436 SudoPassword := SudoPassword + LineEnding;
429437 Proc.Input.Write(SudoPassword[1], Length(SudoPassword));
430438 SudoPassword := '%*'; //short string, hope this will scramble memory a bit; note: using PChars is more fool-proof
431439 SudoPassword := ''; // and make the program a bit safer from snooping?!?
432440
433441 // main loop to read output from stdout and stderr of sudo
434442 while Proc.Running or (Proc.Output.NumBytesAvailable > 0) or
435443 (Proc.Stderr.NumBytesAvailable > 0) do
436444 begin
437445 // read stdout and write to our stdout
438446 while Proc.Output.NumBytesAvailable > 0 do
439447 begin
440448 ReadCount := Min(512, Proc.Output.NumBytesAvailable); //Read up to buffer, not more
441449 Proc.Output.Read(CharBuffer, ReadCount);
442450 Write(StdOut, Copy(CharBuffer, 0, ReadCount));
443451 end;
444452 // read stderr and write to our stderr
445453 while Proc.Stderr.NumBytesAvailable > 0 do
446454 begin
447455 ReadCount := Min(512, Proc.Stderr.NumBytesAvailable); //Read up to buffer, not more
448456 Proc.Stderr.Read(CharBuffer, ReadCount);
449457 Write(StdErr, Copy(CharBuffer, 0, ReadCount));
450458 end;
451459 end;
452460 ExitCode := Proc.ExitStatus;
453461 finally
454462 Proc.Free;
455463 Halt(ExitCode);
456464 end;
457465 end;
458466
459467 begin
460468 RunsLsRoot;
461469 end.
462470```
463471
464472   Otras cuestiones:
465473
466474   Sería, sin duda, aconsejable ver si realmente *sudo* pide una contraseña. Esto se puede comprobar consistetemente estableciendo la variable de entorno *SUDO_PROMPT* a algo que tener en cuenta mientras la lectura de la salida estándar de ***TProcess*** para evitar el problema de que el sistema es diferente para diferentes idiomas. Configurar una variable de entorno hace que los valores predeterminados (heredados de nuestro proceso) se borren, así que tenemos que copiar el entorno de nuestro programa, si es necesario.
467475
468476### Parámetros que contienen espacios (Reemplazar comillas del interprete)
469477
470478   En el interprete de Linux, es posible escribir los argumentos entrecomillados así:
471479
472-` gdb --batch --eval-command="info symbol 0x0000DDDD" miprograma`
480+```text
481+ gdb --batch --eval-command="info symbol 0x0000DDDD" miprograma
482+```
473483
474484   Y GDB recibirá 3 argumentos (además del primer argumento que es la ruta completa al ejecutable):
475485
476-` #--batch`\
477-` #--eval-command=info symbol 0x0000DDDD`\
478-` #la ruta completa a miprograma`
486+```text
487+ #--batch
488+ #--eval-command=info symbol 0x0000DDDD
489+ #la ruta completa a miprograma
490+```
479491
480492   **TProcess** además pasa los parámetros que contengan espacios, pero utiliza un estilo diferente de entrecomillado. En lugar de sólo entrecomillar parte del parámetro, entrecomilla todo él. Tal que así:
481493
482-` TProcess.CommandLine := '/usr/bin/gdb --batch "--eval-command=info symbol 0x0000DDDD" /midirectorio/yo/miprograma';`
494+``` pascal
495+ TProcess.CommandLine := '/usr/bin/gdb --batch "--eval-command=info symbol 0x0000DDDD" /midirectorio/yo/miprograma';
496+```
483497
484498   Y también recuerda pasar sólo rutas completas.
485499
486500   Véase también la discusión al respecto: <http://bugs.freepascal.org/view.php?id=14446>
487501
488502## Alternativas
489503
490504   A veces, no es necesario llamar explícitamente a un programa externo para obtener la funcionalidad que necesitas. A continuación se presentan algunos ejemplos
491505
492506### Abrir una página web en el navegador web predeterminado
493507
494508   Algo así sería más fácil:
495509
496510``` pascal
497511 uses LCLIntf;
498512 ...
499513 OpenURL(URL);
500514```
501515
502516   Sin embargo, puedes utilizar algo como esto:
503517
504518``` pascal
505519 uses Process, LCLIntf;
506520
507521 procedure OpenWebPage(URL: string);
508522 // Apparently you need to pass your URL inside ", like "www.lazarus.freepascal.org"
509523 var
510524 Browser, Params: string;
511525 begin
512526 FindDefaultBrowser(Browser, Params);
513527 with TProcess.Create(nil) do
514528 try
515529 Executable := Browser;
516530 Params:=Format(Params, [URL]);
517531 Params:=copy(Params,2,length(Params)-2); // elimina "", la nueva versión de TProcess.Parameters los hace por sí mismo
518532 Parameters.Add(Params);
519533 Options := [poNoConsole];
520534 Execute;
521535 finally
522536 Free;
523537 end;
524538 end;
525539```
526540
527541## Ver también
528542
529543- [[TXMLPropStorage/es|TXMLPropStorage]]
530544- [[Webbrowser]]
531545
532546---
533547*From the Free Pascal wiki, page "Executing External Programs/es", as it stood on 2020-08-26 after a change by Iskraelectrica, 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).*
534548Category: Castellano
535549Category: Español

Back to history