28 junio 2007

Ejecutar un programa y esperar a que termine

Uno de los problemas habituales con los que se enfrenta un programador es que su cliente le pida algo que o bien no sabe como programarlo o no dispone del componente o librería necesaria para llevar tu tarea a cabo.

Un ejemplo puede ser realizar una copia de seguridad en formatos ZIP, RAR, 7Z, etc., convertir de un formato de video o sonido a otro e incluso llamar a comandos del sistema para realizar procesos criticos en un servidor. Entonces sólo se nos ocurre llamar a un programa externo que realice la tarea por nosostros (y que soporte parámetros).

Sé lo que estáis pensando (la función WinExec), pero en este caso no me vale ya que el programa tiene que esperar a que termine de ejecutarse antes de pasar al siguiente proceso.

Aquí os muestro un procedimiento que ejecuta un programa y se queda esperando a que termine:

function EjecutarYEsperar( sPrograma: String; Visibilidad: Integer ): Integer;
var
sAplicacion: array[0..512] of char;
DirectorioActual: array[0..255] of char;
DirectorioTrabajo: String;
InformacionInicial: TStartupInfo;
InformacionProceso: TProcessInformation;
iResultado, iCodigoSalida: DWord;
begin
StrPCopy( sAplicacion, sPrograma );
GetDir( 0, DirectorioTrabajo );
StrPCopy( DirectorioActual, DirectorioTrabajo );
FillChar( InformacionInicial, Sizeof( InformacionInicial ), #0 );
InformacionInicial.cb := Sizeof( InformacionInicial );

InformacionInicial.dwFlags := STARTF_USESHOWWINDOW;
InformacionInicial.wShowWindow := Visibilidad;
CreateProcess( nil, sAplicacion, nil, nil, False,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
nil, nil, InformacionInicial, InformacionProceso );

// Espera hasta que termina la ejecución
repeat
iCodigoSalida := WaitForSingleObject( InformacionProceso.hProcess, 1000 );
Application.ProcessMessages;
until ( iCodigoSalida <> WAIT_TIMEOUT );

GetExitCodeProcess( InformacionProceso.hProcess, iResultado );
MessageBeep( 0 );
CloseHandle( InformacionProceso.hProcess );
Result := iResultado;
end;

El parámetro iVisibilidad puede ser:

SW_SHOWNORMAL -> Lo normal
SW_SHOWMINIMIZED -> Minimizado (ventanas MS-DOS o ventanas no modales)
SW_HIDE -> Oculto (ventanas MS-DOS o ventanas no modales)

La función devuelve un cero si la ejecución terminó correctamente.

Por ejemplo para ejecutar la calculadora de Windows y esperar a que termine:

procedure EjecutarCalculadora;
begin
if EjecutarYEsperar( 'C:\Windows\System32\Calc.exe', SW_SHOWNORMAL ) = 0 then
ShowMessage( 'Ejecución terminada con éxito.' )
else
ShowMessage( 'Ejecución no terminada correctamente.' );
end;

Pruebas realizadas en Delphi 7.

5 comentarios:

Joaquin Rene dijo...

muy bueno este codigo! te felicito. Muchas gracias

IRCo dijo...

Este es el valor del internet y la gente valiosa que aporta algo. Excelente tu codigo y a casi 6 años de su publicacion me fue extraordinariamente util, mil gracias. Ojala nunca depuren esto ni el blog completo, ojala lo continuaran con temas actuales sin eliminar nada de lo (viejito) publicado.

Mil gracias y felicidades.

Saludos

Unknown dijo...

Excelente!! Me resolvio un problema que tenia pendiente resolver hace mucho.

Muchas gracias.

Unknown dijo...

Años y años de ojear tu blog para una cosa u otra y jamás te di las gracias.
Muy desconsiderado de mi parte.
Ojalá sigas con esto o te esté yendo excelente en tu trabajo y proyectos!!
MUCHAS GRACIAS!!!

Unknown dijo...

Muchas gracias. Tu código me funciono de maravilla.

Publicidad