PDA

Ver la Versión Completa : Thread bendito thread...se me pierde la ventana


Seba.F1
26-01-2006, 23:35:20
Hola gente como andan? llevo mas de 3 horas buscando en los foros de club delphi e internet algo que me ayude con mi problema pero no encuentro nada, si no les molesta a los que mas saben por favor denme una mano, o un pie o algo por favor!!!!!!!! estoy por volverme loco.

EL PROBLEMA
He desarrollado una aplicación que entre muchas cosas, lee datos de una balanza electrónica que pesa camiones (cuando comence con el desarrollo ya estaba). La cuestión es que esta balanza usa un ejecutable en DOS (si Disk Operating Sistem de Micro...), cuando lo ejecuto con cierta sintaxis me devuelve el valor del peso en un archivo .txt. Hasta aca todo bien. Por cuestiones de tiempo (demoras del archivito, mostrar los datos, etc) tuve que implementar un thread para que la aplicación pueda realizar otras tareas mientras pesa los camiones, y ejecuto dentro del thread el programita de la balanza, luego leo el archivo .txt y muestro el numerito en LA aplicación, cuando deja de pesar, se termina el thread, imprime el ticket y cuando cierro la ventana de la balanza, puuuuuuuuffffff,!"·$·$|@#~&·$&|@#~%&|@#~€|34% me tira el siguiente error (obviamente le meti un par de try except... y muestra un lindo mensajito).

Error Win32 Code1400
El identificador de la ventana no es válido

todo bien hasta que se quiere volver a abrir la ventana de la balanza.

Ya existe un componente con el nombre F_Balanza.

y no me lo deja crear, y cuando cierro la aplicaciópn paaaaaaassfff

violacion de acceso a la direccion 7c928fea en el módulo ntdll.dll

aca va el codigo de mi thread, junto con el que dispara el ejecutable de la balanza.

por favor les pido que si alguien me pude decir donde le estoy errando, porque ya no veo nada.



function T_Lectura_Balanza.Ejecutar(const AppName, Params:String):THandle;
var
ProcInfo:TProcessInformation;
Info:TStartupInfo;
begin
FillChar(Info,SizeOf(Info),0);
Info.cb:=SizeOf(Info);
Info.dwFlags:=STARTF_USESHOWWINDOW;
info.wShowWindow:=SW_HIDE;
if not CreateProcess(nil, pchar(AppName+' '+Params),nil,nil,False,0,nil,nil,Info,ProcInfo) then
raise Exception.Create('No se puede iniciar la lectura de la balanza.');
Result:=ProcInfo.hProcess;
end;
procedure T_Lectura_Balanza.Esperar(H:THandle);
begin
while WaitForSingleObject(H,100)=WAIT_TIMEOUT do
begin
Application.ProcessMessages;
if Application.Terminated then
Break;
if F_Balanza.Terminar then
Break;
end;
end;


procedure T_Lectura_Balanza.Execute;
begin Linea_Comando:=MD_Config.IBQ_CONFIGLINEA_COMANDO_BALANZA.AsString;
repeat
try
Esperar(Ejecutar(Linea_Comando,''));
Archivo_Peso:=F_Principal.Dir+'Peso';
F_Balanza.Memo_Peso.Lines.LoadFromFile(Archivo_Peso);
Archivo_Peso:=F_Balanza.Memo_Peso.Lines[0];
if Archivo_Peso='E' then
begin
F_Balanza.Img_Error.Visible:=True;
end
else
begin
F_Balanza.Img_Error.Visible:=False;
Peso:=Copy(Archivo_Peso,2,(Length(Archivo_Peso)-1));
try
Long_:=StrToFloat(Peso);
except
Long_:=0;
end;
if Long_=0 then
F_Balanza.Img_Cero.Visible:=True
else
F_Balanza.Img_Cero.Visible:=False;
F_Balanza.Kg:=Long_;
Decodificar_Numero(Long_,CM,DM,UM,C,D,U);
Mostrar(CM,DM,UM,C,D,U);
end;
except
Decodificar_Numero(0,CM,DM,UM,C,D,U);
Mostrar(CM,DM,UM,C,D,U);
F_Balanza.Img_Cero.Visible:=True;
end;
until F_Balanza.Terminar;
end;

desde ya muchas gracias.

roman
27-01-2006, 00:11:36
No entiendo demasiado de hilos pero siento que tu código está muy enredado.

¿Para qué pones al WaitForSingleObject dentro de un while? En principio, no se pasará de esa línea hasta que no se cumpla el tiempo especificado y si no quieres que termine después de ese tiempo pones INFINITE como timeout y sólo terminará hasta que se cumpla la condición (que termine la otra aplicación)

Y así mismo, no entiendo para qué usas un repeat en el método execute. Si el WaitForSingleObject esta en INFINITE, el método Execute no terminará hasta que no acabe la otra aplicación.

Por otra parte no estoy seguro de si realmente es necesario usar un thread aparte. Cuando uses la balanza podrías poner algo como:


EjecutarBalanza;

DeleteFile('archivo.txt');

repeat
Application.ProcessMessages;
until FileExists('balanza.txt') or Application.Terminated;

ShowMessage('Ya terminó');


// Saludos

seoane
27-01-2006, 01:21:43
Solo un par de detalles. No deberias de utilizar componentes de un formulario desde un Thread sin usar el metodo "Synchronize".

Segundo, como haces para cerrar y mostrar la ventana F_Balanza porque puede que el problema este ahi y no en el thread.

Por ultimo la solucion de Roman me parece sencilla y deberia de funcionar de maravilla. Aunque al escribirlo CREO que no lo hizo en el orden correcto, deberia de ser:


DeleteFile('balanza.txt');
EjecutarBalanza;
repeat
Application.ProcessMessages;
until FileExists('balanza.txt') or Application.Terminated;
ShowMessage('Ya terminó');


Si me equivoco, perdoname ...

roman
27-01-2006, 01:36:24
CREO que no lo hizo en el orden correcto, deberia de ser:


¡Claro!, Tienes toda la razón. Probé el resto de la solución pero no tenía una de esas balanzas a la mano :D. Gracias por la aclaración.

// Saludos

Seba.F1
28-01-2006, 13:16:12
No entiendo demasiado de hilos pero siento que tu código está muy enredado.

hola roman como andás agradezco mucho la respuesta.
te aclaro algunas cositas porque no fui muy claro.

¿Para qué pones al WaitForSingleObject dentro de un while? En principio, no se pasará de esa línea hasta que no se cumpla el tiempo especificado y si no quieres que termine después de ese tiempo pones INFINITE como timeout y sólo terminará hasta que se cumpla la condición (que termine la otra aplicación)

el WaitForSingleObject lo puse para que espere un ratito y se fije en la cola de mensajes a ver cuando termina la ejecución de la aplicacion cuando encuentra la finalización sale del while.

Y así mismo, no entiendo para qué usas un repeat en el método execute. Si el WaitForSingleObject esta en INFINITE, el método Execute no terminará hasta que no acabe la otra aplicación.

el repeat lo utilizo como pooling para ejecutar las otras tareas, hasta que el formulario F_Balanza dice que termine, ya que los camiones están durante algun tiempo en la balanza y se les agrega o saca granos para llegar a los kg exactos con los que pueden usar las rutas.

Por otra parte no estoy seguro de si realmente es necesario usar un thread aparte. Cuando uses la balanza podrías poner algo como:


EjecutarBalanza;

DeleteFile('archivo.txt');

repeat
Application.ProcessMessages;
until FileExists('balanza.txt') or Application.Terminated;

ShowMessage('Ya terminó');


esta version la estoy probando.
si se les ocurre algo nuevo lo agradecere mucho.
un saludo a todos.

// Saludos

Seba.F1
02-02-2006, 00:16:30
Gracias chicos por la ayuda, la solucion la encontre en una combinación de las soluciones planteadas, por un lado roman utilice el borrar y verificar la existencia del archivo delpeso, con eso se me acabaron los problemas con la lectura del archivo, y por otro lado con el infinite en el waitforsingleobject, con eso anduvo barbaro.
por otro lado gracias seoane por el dato del syncronize no sabia que lo tenia que usar es mas el tthread te lo sugiere cuando lo creas, que tonto de mi parte.

bueno chicos nuevamente gracias por la ayuda y solucion de mi problema. saludos seba.:o