PDA

Ver la Versión Completa : Problema con WinExec.


Drahcir
13-06-2007, 15:37:42
Hola a todos,

tengo un problema al que no he encontrado solución y me trae de cabeza. El caso es que en una aplicación en Delphi5 tengo una llamada a una rutina .exe mediante un WinExec... Dicha rutina lo que hace es generar un fichero de salida, tras el WinExec realizo una parada de un segundo y abro el fichero de salida para meter los datos en un StringList (que recorro para tomar solo ciertos datos). El problema es que depende en que equipo tras la primera ejecucion de la rutina me sale el error de que no encuentra el fichero de salida (porque la rutina todavía no lo ha "soltado"), he puesto un control de que si todavía está en modo ReadOnly no siga pero nada.

Mi pregunta es la siguiente, tengo alguna forma de saber, tras hacer el WinExec como puedo saber que ha terminado la rutina para proseguir con el proceso???

Muchas gracias, saludos.

loxod
13-06-2007, 19:48:29
checate este link te pudiera servir

http://www.q3.nu/trucomania/ftesp.html

cHackAll
13-06-2007, 21:05:48
Lastimosamente esta un poco complicado utilizando la API WinExec, La forma de hacerlo es listar los procesos y comprobar cuando el que creaste es terminado. El gran problema de esto (y no digo que se pueda hacer), es que puede existir un proceso con el mismo nombre que haya sido creado con anterioridad, en ese entonces que sucedera? cómo sabras cual creaste tu? obviamente se puede! pero no me parece la forma correcta.

Te dejo un par de APIs que te serán más util:


var
si: TStartupInfo = (cb: SizeOf(TStartupInfo));
pi: TProcessInformation;

procedure TForm1.Button1Click(Sender: TObject);
begin
CreateProcess(nil, 'c:\windows\system32\notepad.exe', nil, nil, False, 0, nil, nil, si, pi);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
if WaitForSingleObject(pi.hProcess, 0) = WAIT_OBJECT_0 then
MessageBox(0, 'La aplicacion ha terminado, corre la siguiente!', nil, 0)
else
MessageBox(0, 'Todavia, espera!', nil, 0)
end;


0j0 que solo es para prueba, si no conoces la API te la explico: CreateProcess es la API que internamente utiliza el WinExec y otros. te permite un control un poco mas "avanzado" del nuevo proceso creado.

Yo pongo la estructura TStartupInfo como global pues la puedo inicializar en tiempo de diseño, si fuese local tendria que llamar a FillChar(0..., y luego a si.cb := SizeOf...
La estructura TProcessInformation es global pues debo poder saber el momento en que el nuevo proceso es liberado.

Finalmente el Button1 "corre" al Block de notas y el Button2 verifica si la aplicacion aún está en ejecucion con la API WaitForSingleObject utilizada para la sincronizacion (Mutex, Pipes, etc, etc).

Espero te sirva. Suerte!

Drahcir
14-06-2007, 08:29:15
Muchas gracias a ambos, tendré en cuenta vuestras aportaciones. De todas formas para salir del paso se me ha ocurrido crear un bucle a la hora de hacer el LoadFromFile del fichero de salida que es el paso que me da problemas a no existir en algunos casos (por cuestión de tiempo) dicho fichero...algo así

e := 1
while e = 1 do begin
try
begin
TStringList.LoadFromFile('C:\TEMP\FICHERO.DAT');
e := 2;
end;
except
e := 1;
end;
end;

No es lo que se diga elegante pero supongo que me servirá para salir del paso.

Saludos.

cHackAll
15-06-2007, 00:41:38
Corrigeme si me equivoco, me parece que estas esperando la "presencia" de un archivo? osea que sea creado o que se pueda tener acceso?


repeat Sleep($7F);
// Application.ProcessMessages;
until CloseHandle(CreateFile('C:\TEMP\FICHERO.DAT', GENERIC_READ, FILE_SHARE_READ + FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0));
ListBox1.Items.LoadFromFile('C:\TEMP\FICHERO.DAT');


Esa es la forma que yo utilizaría en ese caso particularmente, si no utilizas un Sleep parecera que el equipo anda laburando como loco.
Si no utilizas éste procedimiento de "espera" en un hilo te aconsejo quitar el comentario (//) para que tu aplicacion no aparente estar colgada.

Es lo que buscas? suerte!

Drahcir
15-06-2007, 08:28:57
Efectivamente mi problema es que espero un fichero. La rutina que ejecuto con el winexec devuelve un fichero que yo tengo que cargar en un TStringLista para extraer ciertos datos....y ese es el problema ya que en ocasiones me adelanto a tomar el fichero y; o todavía no está, o no se encuentra disponible aún existiendo.

Lo que tu me indicas tiene muy buena pinta y por lo menos es más elegante que mi "bucle loco". Lo comprobaré tan pronto pueda ya que ahora mismo la aplicación ya está siendo usada por el usuario.

Muchas gracias.

Saludos.