PDA

Ver la Versión Completa : Error AccessViolation que no consigo localizar


radge
18-07-2008, 11:52:02
Tengo un formulario con los siguientes componentes :
-Tquery
-dataset
-dbgrid

Lo que hago es hacer una sql con la query y mostrar la en el GRID , una vez alli muestro los campos y tengo un checkbox dependiendo si lo chekeas o no hace una sql o otra.

Un formulario realmente sencillo

La cuestión es que en el gris empiezo a “toketearlo” y cada cierto número de veces que apreto en el grid , pueden ser 10..30..40 o 2… depende…. Me sale la siguiente excepción

Project Proyecto1.exe raised exception class EAccessVioaltion with message
‘Access violation at address 004032AE in module Proyecto1.exe.
Read of address FFFFFFDC’. Process stopped….


Alguna vez rara vez he visto esta otra

Exception EAccessViolation in module Comerciales.exe at 00000000.
Access violation at address 00000000. Read of Address 00000000






Os pondria el código pero sin la sql y tal no serviria de nada ;(


he debugado y debugado pero no le veo el fallo....


salu2 radge

Neftali [Germán.Estévez]
18-07-2008, 12:26:57
Compila el código añadiendo opciones de Debug.
Una vez que estés ejecutando, prueba a ir a las opciones de Search/Find Error e introduce el primer número hexadecimal (address) a ver si por ahí aclaras algo.

http://img187.imageshack.us/img187/1003/imagen480bp4.png

radge
18-07-2008, 12:36:15
Adjunto imagen de las opciones que tengo al compilar

http://img258.imageshack.us/my.php?image=sinttulo1ue9.jpg



Con la dirección que me da la pongo dodne me has dicho y lo que me sale no se descifrarlo
http://img403.imageshack.us/img403/8094/sinttulo2vl1.th.jpg (http://img403.imageshack.us/my.php?image=sinttulo2vl1.jpg)

gracias , radge

coso
18-07-2008, 12:42:48
Hola, debes tener la informacion de debug activada (project->options->compiler->debug options) para que te indique encima de tu codigo en que linea te salta la excepción. Es mas, si pones en 'tools->debugger options->Halt on delphi exceptions', y pulsas Ctrl+F3 una vez te ha saltado la excepcion (dentro del IDE), sabras cuales han sido las funciones llamadas antes de la excepcion.

radge
18-07-2008, 16:05:37
Hola, debes tener la informacion de debug activada (project->options->compiler->debug options) para que te indique encima de tu codigo en que linea te salta la excepción. Es mas, si pones en 'tools->debugger options->Halt on delphi exceptions', y pulsas Ctrl+F3 una vez te ha saltado la excepcion (dentro del IDE), sabras cuales han sido las funciones llamadas antes de la excepcion.

Gracias pongo la dirección en Hex. en find/search error del delphi y siempre me sale la misma dirección 004825E7

Resulta que es código suyo propio , como arreglo esto ¿?

http://img144.imageshack.us/img144/1147/fallo3iu9.jpg (http://imageshack.us)
http://img144.imageshack.us/img144/1147/fallo3iu9.24caa3fd55.jpg (http://g.imageshack.us/g.php?h=144&i=fallo3iu9.jpg)


gracias , radge

Neftali [Germán.Estévez]
18-07-2008, 16:37:14
¿Tienes la pila de llamadas de ese error?

View/Debug Windows/Call Stack

¿Puedes ponerla?

radge
18-07-2008, 16:40:48
Si claro aki esta a ver k os parece.

http://img528.imageshack.us/img528/8318/fallo4jx1.jpg (http://imageshack.us)
http://img528.imageshack.us/img528/8318/fallo4jx1.ff13329503.jpg (http://g.imageshack.us/g.php?h=528&i=fallo4jx1.jpg)

gracias , radge

radge
18-07-2008, 17:47:50
Os pongo un eskema de lo k hace mi evento FieldChanged del wwdbgrid que como vereis es muy simple


procedure formulario1.wwDBGrid1FieldChanged(Sender: TObject; Field: TField);

begin
if (condicion1) then begin
SQL1 (INSERT INTO)
SQL2 (UPDATE)
end
else begin
Creo un formulario para rellenar unos datos
y los recibo en el formulario actual
Una vez recibido los datos lo destruyo.
SQL3 (INSERT INTO)
SQL4 (UPDATE)
end;
end


gracias , radge

coso
18-07-2008, 19:09:34
si el fallo seguro que no esta en esquema, sino en algun detalle. Antes del codigo en el onchange, yo pondria if not (sender as TDBEdit).Focused then exit;

radge
21-07-2008, 08:11:21
si el fallo seguro que no esta en esquema, sino en algun detalle. Antes del codigo en el onchange, yo pondria Código Delphi [-] (http://www.clubdelphi.com/foros/#) if not (sender as TDBEdit).Focused then exit;




Te refieres en el onfieldchanged ? Y eso que hace exactamente ? Porque yo no tengo ningun TDBEdit.

Te referias al onchange del formulario o del dbgrid ?

gracias , radge

coso
21-07-2008, 10:15:52
vaya, hubiese dicho que era dbedit. De igual manera, si, en el on fieldchange

PD : Read of address FFFFFFDC : Esto son ya las ultimas direcciones de memoria... creo que hay algo que no liberas correctamente y te va comiendo memoria.
PDD : lo que hace es que evita calculos si no esta el formulario correctamente inicializado, etc...vamos, si no tiene el foco. Para evitar actualizaciones indeseadas o incontroladas mas bien.

radge
21-07-2008, 10:22:16
if not (sender as wwDBGrid1).focused then exit;

Me dice

[Error] SupVision.pas(203): Operator not applicable to this operand type



En cuanto lo de la memoria ya lo pensé yo pero lo unico que creo es un formulario que luego destruyo antes de volver a utilizarlo

salu2 radge

radge
21-07-2008, 10:45:26
Casi todo el rato me apunta aquí


http://img144.imageshack.us/img144/1147/fallo3iu9.jpg (http://imageshack.us)

Es como si intentara liberar buffer o algo similar y da error ? Van x aki los tiros ?

salu2 radge
http://img144.imageshack.us/img144/1147/fallo3iu9.24caa3fd55.jpg (http://g.imageshack.us/g.php?h=144&i=fallo3iu9.jpg)

coso
21-07-2008, 11:09:50
if not (sender as TDBGrid).Focused ... esto interpreta a 'sender' como de la clase DBGrid (si no lo fuera, por ejemplo si sender fuese un edit, te saltaria excepcion).

Pues en el momento que te salga la excepcion (en delphi, no en el programa) aprietas Ctrl+F3, te sale el stack. La primera linea es la ultima funcion llamada, y las siguientes las anteriores. El debugger te apunta a el codigo nativo pues es alli donde salta, aunque seguramente se haya provocado en una de las tuyas :entonces miras mediante esta lista cual de tus funciones ha sido la ultima en llamarse que ha provocado el error, y en que linea. Venga, suerte a ver si lo encuentras.

radge
21-07-2008, 11:19:32
if not (sender as TDBGrid).Focused ... esto interpreta a 'sender' como de la clase DBGrid (si no lo fuera, por ejemplo si sender fuese un edit, te saltaria excepcion).

Pues en el momento que te salga la excepcion (en delphi, no en el programa) aprietas Ctrl+F3, te sale el stack. La primera linea es la ultima funcion llamada, y las siguientes las anteriores. El debugger te apunta a el codigo nativo pues es alli donde salta, aunque seguramente se haya provocado en una de las tuyas :entonces miras mediante esta lista cual de tus funciones ha sido la ultima en llamarse que ha provocado el error, y en que linea. Venga, suerte a ver si lo encuentras.

Gracias , pero el problema que el onfield changes apenas tiene 50 0 60 lineas he puesto varios try catch para ver donde me salta la excepción pero no hay forma de que salte en el delphi , pero si en el programa.

Entonces por eso no se donde pillar lo , porque no se lo que o donde lo esta provocando.

salu2 radge

coso
21-07-2008, 11:26:41
a eso voy... cuando te salga la excepcion, aprietas Ctrl+F3 y te sale la lista de las llamadas a funciones. Olvidandote del codigo nativo, que esta correcto, tu vas a tu funcion y veras en que linea se te ha provocado y entonces puedes deducir porque. Saludos.

pero no hay forma de que salte en el delphi tools->debugger options->exception->stop on delphi exceptions

esto anterior te hara saltar la excepcion en delphi aunque la tengas en un try

apenas tiene 50 0 60 lineas

y ya son demasiadas. divide y venceras.

radge
22-07-2008, 08:29:24
else if (FilaCheck = 'N') then
if (var1= var2) then begin
botoseleccionat := MessageDlg('Estas seguro que quieres borrar las unidades servidas ?',mtCustom,
[mbYes,mbNo], 0);
if botoseleccionat = mrYes then begin
cadenaSQL := 'update sql';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
cadenaSQL := 'update SQL';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
try
query_supvision.Close;
query_supvision.Open;
except
showmessage('Error abriendo la base de datos');
end
end
end


He debugado y debugado y uno de las veces al mirar el "call stack" me marca en esta posición , pero yo no le veo nada a esta linea de codigo.

gracias radge

coso
22-07-2008, 09:27:34
debugar es fastidioso :mad:, y hacerlo online, un poco mas :confused:. Otro truquito que se hace es ir comentando lineas, probando, comentando lineas, ... hasta que no te salte. Es raro, porque esa linea de codigo no tiene nada ciertamente...a no ser que, como deciamos, ya no tengas memoria ni para llenar un TModalResult...No se si cargas un exceso de datos por algun otro lado que no liberas, alguna form que creas varias veces en tiempo de ejecucion, querys que se crean y llaman multitud de veces (ejecutar_SQL) sin luego liberarlas,bitmaps,...ni idea, deberia repasar todo el codigo. Si tienes alguna otra duda, por eso, no dudes en ponerla aqui. Venga, saludos, i sort!;)

PD : prueba de ponerlo en otro evento que no sea el OnFieldChanged, pues ahora que pienso, si modificas la misma base de datos que se mira en el DBGrid, es probable que la llames recursivamente una y otra vez. Saludos.

coso
22-07-2008, 09:35:33
Si puedes, pon el codigo entero de
procedure formulario1.wwDBGrid1FieldChanged(Sender: TObject; Field: TField)


Exception EAccessViolation in module Comerciales.exe at 00000000.
Access violation at address 00000000. Read of Address 00000000

este es otro completamente independiente, seguro

radge
22-07-2008, 15:25:56
procedure TfrmSupVision.wwDBGrid1FieldChanged(Sender: TObject;
Field: TField);
Var
cadenaSQL,FilaCheck,Lin_Codi,Alb_Codi,Per_Codi,accountnum,dataareaid ,
varDades , varUnitatsRestants : string;
Cantidad , UnitatsServidesBD , botoseleccionat : Integer ;
Marca : TBookMarkStr;

begin
Lin_Codi := query_supvision.FieldbyName('LIN_Codi').AsString;
Alb_Codi := query_supvision.FieldbyName('ALB_Codi').AsString;
Per_Codi := query_supvision.FieldbyName('Per_Codi').AsString;
Accountnum := query_supvision.FieldbyName('accountnum').AsString;
Dataareaid := query_supvision.FieldbyName('dataareaid').AsString;
Cantidad := query_supvision.FieldbyName('Cantidad').asinteger;
UnitatsServidesBD := query_supvision.FieldbyName('Unitats_Servides').asinteger;


if ((Lin_Codi <> '') and (Dataareaid <> '') and (Alb_Codi <> '') and (Per_Codi <> '') and (Accountnum <> '') AND (inttostr(Cantidad) <> '') ) then begin
if (combobox1.text = 'TODOS') then
FreeAndNil(Marca);
Marca := query_supvision.Bookmark;

FilaCheck := wwDBGrid1.GetFieldValue(7);

if (FilaCheck = 'S') then begin
if (Cantidad = 1) then begin
cadenaSQL := 'SQL XXXXXXXXXXX';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
cadenaSQL := 'SQL XXXXXXXXX';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
try
query_supvision.Close;
query_supvision.Open;
except
showmessage('Error al abrir/cerrar BD vuelve a intentar lo');
end;
end

else begin // Si hi ha més d'una unitat d'aquella linea de pedido ==> FORM NOU
try
Application.CreateForm (TfrmUnidadesPedidoVenta, frmUnidadesPedidoVenta);
except
;
end;
frmUnidadesPedidoVenta.CarregaDades(Cantidad,UnitatsServidesBD);
if (Cantidad > 0) and (UnitatsServidesBD >=0 )then begin
frmUnidadesPedidoVenta.ShowModal;
varDades := frmUnidadesPedidoVenta.rebreDades;
varUnitatsRestants := frmUnidadesPedidoVenta.rebreUnitatsRestants;
cadenaSQL := 'SQL XXXXXXXXXXXXXXXXXX';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
cadenaSQL := 'SQL XXXXXXXXXXXXXXXXXX';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
query_supvision.Close;
query_supvision.Open;
end
else begin
showmessage('Error al recibir los datos');
end;
end;
end
else if (FilaCheck = 'N') then
if (Cantidad = UnitatsServidesBD) then begin
botoseleccionat := MessageDlg('Estas seguro que quieres borrar las unidades servidas ?',mtCustom,[mbYes,mbNo], 0);
if botoseleccionat = mrYes then begin
cadenaSQL := 'SQL XXXXXXXXXXXXXXXXXX';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
cadenaSQL := 'SQL XXXXXXXXXXXXXXXXXX';
ModuloDatos.Ejecutar_SQL(cadenaSQL);
try
query_supvision.Close;
query_supvision.Open;
except
showmessage('Error abriendo la base de datos');
end
end
else begin
query_supvision.Cancel; // refrescar
end;
end;
end
else begin
showmessage('Este cliente no tiene más albaranes por editar');
end;
if (combobox1.text = 'TODOS') then
query_supvision.Bookmark := Marca;
end;

coso
22-07-2008, 15:44:08
puedes usar delphi y /delphi entre [], si es codigo delphi. Creas la form, pero en ningun momento la liberas. Yo lo haria asi:


var
f : TfrmUnidadesPedidoVenta;
begin
...
try
f := TfrmUnidadesPedidoVenta.Create(self); // corregido
f.ShowModal;
...
f.free;
except
...


casi seguro que es eso

otra es marca, porque freeandnil si aun no se ha asignado (ni falta que hace)? TBookMarkStr solo es una string, por lo que en principio no te tienes que preocupar de su memoria. El access a nil es debido a eso seguro, pues la liberas y luego intentas trabajar con ella. Si quieres que tenga un valor nulo, simplemente haz marca := '' o marca := nil, pero no la liberes pues se queda desreferenciada en memoria. En tu caso, creo q no hace falta ni siquiera marca := '' pues a lo siguiente ya le das un valor concreto.

Tambien creo q te falta un bloque begin end en ComboBox1.Text = 'TODOS'

radge
23-07-2008, 08:12:12
He cambiado lo que mas dicho del bloque begin y lo de la variable.

Pero lo del formulario lo he dejado asi

Application.CreateForm (TfrmUnidadesPedidoVenta, frmUnidadesPedidoVenta);
frmUnidadesPedidoVenta.CarregaDades(Cantidad,UnitatsServidesBD);
frmUnidadesPedidoVenta.ShowModal;
varDades := frmUnidadesPedidoVenta.rebreDades;
varUnitatsRestants := frmUnidadesPedidoVenta.rebreUnitatsRestants;
frmUnidadesPedidoVenta.Free;


Pero sigue dandome error os dejo la pila. gracias radge


Como veis todas las instrucciones son de código nativa menos la 1º empezando por abajo del stack , que es la marcada en rojo.

http://img70.imageshack.us/img70/3929/sinttulo2mv1.jpg (http://imageshack.us)
http://img70.imageshack.us/img70/3929/sinttulo2mv1.e8b726c8d9.jpg (http://g.imageshack.us/g.php?h=70&i=sinttulo2mv1.jpg)

Neftali [Germán.Estévez]
23-07-2008, 10:48:10
Hay entre las llamadas del callstack algunas especiales:
http://img78.imageshack.us/img78/7859/error1mr1.jpg

Creo que eso te puede dar datos sobre el campo del error.
¿Hay algun campo en el Grid en el que esté apareciendo "N"? ¿Tal vez un booleano?
Deberías revisar si en algun momento ese campo puede no estar asignado.

Neftali [Germán.Estévez]
23-07-2008, 11:01:52
Hay entre las llamadas del callstack algunas especiales:
http://img78.imageshack.us/img78/7859/error1mr1.jpg

Creo que eso te puede dar datos sobre el campo del error.
¿Hay algun campo en el Grid en el que esté apareciendo "N"? ¿Tal vez un booleano?
Deberías revisar si en algun momento ese campo puede no estar asignado.

coso
23-07-2008, 12:09:48
Hola otra vez, probablemente ya tengas una instancia de TfrmUnidadesPedidoVenta con el nombre frmUnidadesPedidoVenta que se te crea de manera automatica (project->options->Forms->autocreateForms). Si es asi, al volver a usar ese nombre estas dejando toda la form anterior en memoria desreferenciada. Has probado si con el codigo anterior, tal cual esta, te salta el error? luego, al quedarse sin memoria, te puede saltar en cuqlquier momento. Tambien, query_supvision etc esta todo correcto no? en cuanto a creacion y liberacion.

coso
23-07-2008, 12:13:50
Otra cosa: carregadades tambien esta todo correcto? si vas comentando bloques (por ejemplo, que no te cree el form o la parte de las consultas) te salta el error? es un metodo para localizarlo

radge
23-07-2008, 12:18:27
Ok pruebo esto , de todas formas lo del formulario lo tengo en un try , me deberia saltar y no lo he visto saltar ninguna vez.



try
Application.CreateForm (TfrmUnidadesPedidoVenta, frmUnidadesPedidoVenta);
frmUnidadesPedidoVenta.CarregaDades(Cantidad,UnitatsServidesBD);
frmUnidadesPedidoVenta.ShowModal;
varDades := frmUnidadesPedidoVenta.rebreDades;
varUnitatsRestants := frmUnidadesPedidoVenta.rebreUnitatsRestants;
frmUnidadesPedidoVenta.Free;
except
on e : exception do begin
ShowMessage ('Clase de error: ' + e.ClassName + chr(13) + chr(13) + 'Mensaje del error: ' + e.Message);
end;
end;

coso
23-07-2008, 12:25:39
Bueno, segun la direccion de memoria que te pone (FFFFFFDC), ya casi al final de todo puede que consiga la memoria suficiente para la form, pero luego ya no pueda hacer nada mas, por lo que no tendria que saltar alli ($FFFFFFFF - $FFFFFFDC = $23 = 35 bytes) Por eso que te salte a las 30 o 40 veces. Yo creo que es eso, quiza me equivoque claro esta :p. Saludos

radge
23-07-2008, 12:57:06
Mira te muestro la stack , yo siempre busco la 1º función mia no nativa empezando por arriba no ???

De ser asi toi mirando esto.


http://img78.imageshack.us/img78/5012/sinttulo2vl5.jpg (http://imageshack.us)
http://img78.imageshack.us/img78/5012/sinttulo2vl5.c915f8b0d8.jpg (http://g.imageshack.us/g.php?h=78&i=sinttulo2vl5.jpg)

coso
23-07-2008, 13:06:30
si te fijas, el stack son las funciones que se han ido llamando, que se guardan en esta lista. Asi, si quieres mirar donde ha saltado el error, pues va bien para conocer en que funcion. Ahora bien, segun tu dices te pasa a la 30 o 40 vez que pulsas el click, por lo que no es un error digamos inicial, sino uno que se va arrastrando. Asi pues, el stack aunque te diga donde ha saltado, el inicio del error puede estar en cualquier parte. Como ya te he dicho, yo creo que es porque creas algo repetidas veces sin liberarlo: has probado el codigo anterior, tal cual? f variable local, creandola con el create no con el application.createform, y su free? si aun asi te da error, prueba de comentar el bloque de creacion de esa form, a ver si asi te salta. si es el caso, entonces el error debe estar en alguna de las funciones interiores, carregadades, etc...donde quiza estes cargando datos en un objeto que creas repetidas veces pero no liberas cada vez.

coso
23-07-2008, 13:15:02
ten en cuenta tambien la vision de Neftali: yo estoy fijo en lo de los 30 intentos, pero segun el stack que el te muestra, el error te saltaria por algo completamente diferente.

radge
23-07-2008, 14:55:36
si te fijas, el stack son las funciones que se han ido llamando, que se guardan en esta lista. Asi, si quieres mirar donde ha saltado el error, pues va bien para conocer en que funcion. Ahora bien, segun tu dices te pasa a la 30 o 40 vez que pulsas el click, por lo que no es un error digamos inicial, sino uno que se va arrastrando. Asi pues, el stack aunque te diga donde ha saltado, el inicio del error puede estar en cualquier parte. Como ya te he dicho, yo creo que es porque creas algo repetidas veces sin liberarlo: has probado el codigo anterior, tal cual? f variable local, creandola con el create no con el application.createform, y su free? si aun asi te da error, prueba de comentar el bloque de creacion de esa form, a ver si asi te salta. si es el caso, entonces el error debe estar en alguna de las funciones interiores, carregadades, etc...donde quiza estes cargando datos en un objeto que creas repetidas veces pero no liberas cada vez.

Sisi probé a comentar el trozo de código que creo el form y me salta una excepción igualmente.

Y tambien probé a poner :

f := TfrmUnidadesPedidoVenta(create);

En esa linia me pone [Error] SupVision.pas(203): Not enough actual parameters

coso
23-07-2008, 15:12:33
si bueno,... la sintaxis que es correcta seria -> f := TfrmUnidadesPedidoVenta.Create(nil) o (self), el argumento es el parent form, me debi liar al escribirlo. Igualmente, si al comentarlo (donde lo creas y donde la usas, claro, si es solo donde la creas tendras una excepcion mas) te sigue saltando, es que el error no esta por alla.

radge
23-07-2008, 15:16:42
si bueno,... la sintaxis que es correcta seria -> f := TfrmUnidadesPedidoVenta.Create(nil) o (self), me debi liar al escribirlo. Igualmente, si al comentarlo (donde lo creas y donde la usas, claro, si es solo donde la creas tendras una excepcion mas) te sigue saltando, es que el error no esta por alla.

Exacto creo que el error esta en otra parte , porque lo he comentado las 5 o 6 lineas donde lo creo , recibo los datos y lo destruyo y sigue saltando la excepción.

salu2 radge

coso
23-07-2008, 15:19:53
X) pues tienes faena. saludos.

radge
23-07-2008, 15:28:12
No si llevo más de 2 semanas con esto... pero es que no lo veo la verdad... me he trabado con ello.

gracias , radge

coso
23-07-2008, 15:44:06
mira en el codigo inicial que pusiste, he encontrado errores de los que yo considero graves (la liberacion del string que luego usas, crear una form con un nombre de variable global, probablemente ya creada,...), por lo que, sin animo de despreciar, creo que pueden haber bastantes del mismo tipo por diferentes lugares del proyecto. Le pegaria una repasada general a todo entero teniendo en cuenta :
- no crear forms inecesarias : si solo se usan una vez, usar el autocreate (project->options). Si se han de usar varias a la vez de la misma clase (como por ejemplo seria un preview), entonces si usar el create de las forms.
- si se crean, en tiempo de ejecucion, tanto forms como otros objetos, destruirlos en la misma funcion desde donde se han llamado. Vamos, las ultimas lineas de la funcion tendrian que ser del tipo q.Free, f.Free,...(en teoria, si dentro de estas forms no creas nada en tiempo de ejecucion, no hace falta usar el free, pero no esta de mas)
- si se cargan datos, tener en cuenta que se liberen una vez usados. Si se sale de la funcion donde se ha creado y cargado, entonces usar una variable global del form directamente y en su create darles la memoria (a todos los que vayas a usar) y en el create del objeto, hacer create(self) , o sea vinculado a la form, y en el evento destroy liberar estos objetos (solo en el destroy). Asi mientras este creada la form tendras esos objetos a mano siempre.
- Lo que decia neftali, vigilar que los campos de tus query esten creados y correctamente escritos y llamados, y que se asignen valores de acuerdo a sus tipos.
- Y lo que te comente al principio: usar los breakpoints (F5) los watches (Ctrl+F5), F7,F8 , el call stack, y lo de comentar/descomentar.


Venga, haber si lo resuelves. Saludos

coso
23-07-2008, 15:56:15
Otra manera es usando un administrador de memoria y ir haciendo f7s,f8s...en los momentos en los que se te carguen bloques de memoria exagerados y alla se queden, por alla tendrias el problema (siempre suponiendo q el error sea por agotamiento de memoria, claro)

radge
23-07-2008, 16:29:08
Como variable global creo esta "CodiClient" que es una variable que arrastro de un combobox a distintos sitios dentro del mismo formulario.

Lo del auto-create forms solo tengo uno llamado "splash" lo que salta al inicio del programa , solo tengo ese.


El trozo este de codigo

Código Delphi [-] (http://www.clubdelphi.com/foros/#) Application.CreateForm (TfrmUnidadesPedidoVenta, frmUnidadesPedidoVenta); frmUnidadesPedidoVenta.CarregaDades(Cantidad,UnitatsServidesBD); frmUnidadesPedidoVenta.ShowModal; varDades := frmUnidadesPedidoVenta.rebreDades; varUnitatsRestants := frmUnidadesPedidoVenta.rebreUnitatsRestants; frmUnidadesPedidoVenta.Free;



var
frmUnidadesPedidoVenta: TfrmUnidadesPedidoVenta;
unidades_restantes : integer ;
FlagCheckSupervisado : string;
implementation

uses SupVision;

{$R *.DFM}

procedure TfrmUnidadesPedidoVenta.CarregaDades(var1,var2: integer);
begin
UnitatsPedidoVenta := var1;
UnitatsServidesBD := var2;
end;

function TfrmUnidadesPedidoVenta.rebreDades():String;
begin
Result := edit1.Text;
end;

function TfrmUnidadesPedidoVenta.rebreUnitatsRestants(): string;
begin
if (unidades_restantes = strtoint(edit1.text)) then
FlagCheckSupervisado := 'S'
else
FlagCheckSupervisado := 'N';
Result := FlagCheckSupervisado;
end;

procedure TfrmUnidadesPedidoVenta.ACTUALIZARClick(Sender: TObject);
begin

if ( strtoint(edit1.text) = 0) then
showmessage('No es posible añadir 0 unidades ')
else if ( strtoint(edit1.text) > unidades_restantes) then
showmessage('El número máximo permitido es ' + inttostr(unidades_restantes) + ' unidades ')
else
frmUnidadesPedidoVenta.Close;
end;

procedure TfrmUnidadesPedidoVenta.FormShow(Sender: TObject);
begin
label3.Caption := inttostr(UnitatsPedidoVenta);
label4.Caption := inttostr(UnitatsServidesBD);
unidades_restantes := UnitatsPedidoVenta - UnitatsServidesBD;
Label5.Caption := inttostr(unidades_restantes);
end;




procedure TfrmUnidadesPedidoVenta.edit1KeyPress(Sender: TObject;
var Key: Char);
begin
If Key = #13 then
ACTUALIZAR.Click;
end;


end.

coso
23-07-2008, 16:33:51
pues quiza lo mas correcto sea q tengas en autocreate forms todas las forms que vas a usar en el proyecto. O es que las estas creando cada vez que las vas a llamar? si ese es el caso, una vez usadas y cerradas las forms, las destruyes?? porque ten en cuenta que si creas una form y luego vuelves a crearla y llamarla con el mismo nombre de variable sin haber destruido la anterior se queda esta ultima desreferenciada por memoria.

radge
23-07-2008, 16:41:14
Es una aplicación heredada... y el k la empezó no esta xD

Tiene más de 40 formularios y bastante densos.

Por lo que he visto normalmente se usa el formulario.... se crea y se destruye.
Por eso sigo con la misma tónica , lo creo hago sus cositas y al cerrar lo destruimos.

salu2 radge

radge
23-07-2008, 16:45:47
Lo que si que noto que contra más mano le meto.. mas veo de estos

Access violation at address 00000000. Read of Address 00000000

coso
23-07-2008, 16:46:40
Si no fueses un profesional te diria q me pasaras el codigo para echarle un vistazo :D pero asi X). Me da q va por alli, por lo de forms no liberadas y vueltas a referenciar con la misma variable...ya contaras algo, saludos ;)

coso
23-07-2008, 16:48:02
Esos anteriores, claro esta son de objetos o bien liberados y reusados, o bien no creados. Si, como antes, estas liberando antes de usar cosas como el TBookMarkStr, que es una string, te saldran montones de ellos.

radge
23-07-2008, 16:51:00
Gracias eso del string ya lo arregle xD la verdad que llevo varios años programado pero acabo de empezar con delphi 5 en esta empresa y con un proyecto... grande que lleva varios años en desarrollo y no veas como pillo xD

gracias , radge

radge
24-07-2008, 12:36:38
unit SupVision;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, DBTables, Wwquery, Wwdatsrc, Grids, Wwdbigrd, Wwdbgrid,
StdCtrls, wwdbdatetimepicker, wwdblook, Buttons, ExtCtrls , ComCtrls;

type
TfrmSupVision = class(TForm)
DS_supvision: TwwDataSource;
query_supvision: TwwQuery;
UpdateSQL1: TUpdateSQL;
Combo_Clientes: TwwDBLookupCombo;
query_combo: TwwQuery;
ComboBox1: TComboBox;
query_comboname: TStringField;
query_comboaccountnum: TStringField;
Label1: TLabel;
SpeedButton2: TSpeedButton;
Edit1: TEdit;
Label3: TLabel;
Shape7: TShape;
Shape1: TShape;
Shape2: TShape;
BtnImprimir: TBitBtn;
Label5: TLabel;
wwDBGrid1: TwwDBGrid;
procedure Combo_ClientesChange(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
{ procedure Button1Click(Sender: TObject); }
procedure Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormCreate(Sender: TObject);
procedure ComboBox1Click(Sender: TObject);
procedure BtnImprimirClick(Sender: TObject);
procedure Edit1Click(Sender: TObject);
procedure wwDBGrid1TitleButtonClick(Sender: TObject;
AFieldName: String);
procedure wwDBGrid1FieldChanged(Sender: TObject; Field: TField);
private
{ Private declarations }
public
{ Public declarations }
end;

var
frmSupVision: TfrmSupVision;
Field_Sorted, Sort_Type, SQL_Base: string;
CodiClient,cadena2: String; //Variable global per saber el codi del client
FlagE : integer;
implementation

uses ModuloDatos,UnidadesPedidoVenta, PrintPedidosSupervisados;
{$R *.DFM}

function tornarMaxID(): integer;
var cadenaSQLID : string;
query_maxID : TQuery;
begin
query_maxID := TQuery.Create(nil);
query_maxID.DatabaseName := Modulo_Datos.NOG_Comer.DatabaseName;
cadenaSQLID := 'SQLLLLLLLLLLLLLLL' ;
query_maxID.SQL.Clear;
query_maxID.close;
query_maxID.SQL.Add(cadenaSQLID);
query_maxID.open;
Result := query_maxID.Fields[0].Asinteger;
query_maxID.Close;
FreeAndNil(query_maxID);
end;


procedure TfrmSupVision.Combo_ClientesChange(Sender: TObject);
begin

if FlagE = 0 then begin
CodiClient := Combo_Clientes.Lookuptable.FieldByName('accountnum').asstring;
end;

SQL_Base := 'SQL';

if (IntToStr(length(Combo_clientes.text)) > '0') then
SQL_Base := SQL_Base + ' AND A.accountnum = ' + QuotedStr(CodiClient);

if (combobox1.text <> '') then
if combobox1.text = 'SI' then begin
SQL_Base := SQL_Base + ' and Check_supervisado = ' + QuotedStr('S');
end
else if combobox1.text = 'NO' then begin
SQL_Base := SQL_Base + ' and Check_supervisado = ' + QuotedStr('N');
end;

if Edit1.text <> '' then
SQL_Base := SQL_Base + ' SQL XXXXXXXXXXXXX';

try
query_supvision.close;
query_supvision.SQL.Clear;
query_supvision.SQL.Add(SQL_Base);
query_supvision.open;
except
showmessage('Error al cargar los clientes');
end;
FlagE := 0;
end;


procedure TfrmSupVision.SpeedButton2Click(Sender: TObject);
begin
close;
end;

procedure TfrmSupVision.FormClose(Sender: TObject; var Action: TCloseAction);
begin
frmSupVision := nil;
Action := caFree;
end;


procedure TfrmSupVision.Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key = VK_Return then
Combo_ClientesChange (Sender);
end;

procedure TfrmSupVision.FormCreate(Sender: TObject);
begin
Combo_ClientesChange (Sender);
query_combo.Open;
FlagE := 0;
end;

procedure TfrmSupVision.ComboBox1Click(Sender: TObject);
begin
FlagE := 1;
end;

procedure TfrmSupVision.BtnImprimirClick(Sender: TObject);
begin
Application.CreateForm (TfrmPrintPedidosSupervisados, frmPrintPedidosSupervisados);
frmPrintPedidosSupervisados.ShowModal;
end;

procedure TfrmSupVision.Edit1Click(Sender: TObject);
begin
FlagE := 1;
end;


procedure TfrmSupVision.wwDBGrid1TitleButtonClick(Sender: TObject;
AFieldName: String);
begin
Field_Sorted := AFieldName;

if Sort_Type = 'ASC' then
Sort_Type := 'DESC'
else
Sort_Type := 'ASC';

if Field_Sorted = 'ALB_Fecha' then
cadena2 := SQL_Base + ' ORDER BY A.' + AFieldName + ' ' + Sort_Type
else if Field_Sorted = 'name' then
cadena2 := SQL_Base + ' ORDER BY C.' + AFieldName + ' ' + Sort_Type
else
cadena2 := SQL_Base + ' ORDER BY LA.' + AFieldName + ' ' + Sort_Type;

wwdbgrid1.DataSource.DataSet.Close;
(wwdbgrid1.DataSource.DataSet as TwwQuery).SQL.Clear;
(wwdbgrid1.DataSource.DataSet as TwwQuery).SQL.Add(cadena2);
wwdbgrid1.DataSource.DataSet.Open;
end;


procedure TfrmSupVision.wwDBGrid1FieldChanged(Sender: TObject;
Field: TField);
Var
cadenaSQL,FilaCheck,Lin_Codi,Alb_Codi,Per_Codi,accountnum,dataareaid ,
varDades , varUnitatsRestants : string;
Cantidad , UnitatsServidesBD , botoseleccionat : Integer ;
Marca : TBookMarkStr;
begin
try
Lin_Codi := query_supvision.FieldbyName('LIN_Codi').AsString;
Alb_Codi := query_supvision.FieldbyName('ALB_Codi').AsString;
Per_Codi := query_supvision.FieldbyName('Per_Codi').AsString;
Accountnum := query_supvision.FieldbyName('accountnum').AsString;
Dataareaid := query_supvision.FieldbyName('dataareaid').AsString;
Cantidad := query_supvision.FieldbyName('Cantidad').asinteger;
UnitatsServidesBD := query_supvision.FieldbyName('Unitats_Servides').asinteger;
except
showmessage('No se han podido cargar los datos del albarán');
query_supvision.cancel;
end;
if ((Lin_Codi <> '') and (Dataareaid <> '') and (Alb_Codi <> '') and (Per_Codi <> '') and (Accountnum <> '')) then begin
if (combobox1.text = 'TODOS') then begin
try
Marca := query_supvision.Bookmark;
except
showmessage('error cargando formulario');
end;
end;

FilaCheck := wwDBGrid1.GetFieldValue(7); // Si cambiem l'ordre del grid cambiar el GetFieldValue

if (FilaCheck = 'S') then begin
// 1 unitat , fiquem la data i l'introduim a la BD
if (Cantidad = 1) then begin
cadenaSQL := 'SQL 111111111';
Ejecutar_SQL(cadenaSQL);

cadenaSQL := 'SQL 2222222';
Ejecutar_SQL(cadenaSQL);
try
query_supvision.Close;
query_supvision.Open;
except
showmessage('No se han podido aplicar los cambios en la Base de datos');
end;
end
else begin // Si hi ha més d'una unitat d'aquella linea de pedido ==> FORM NOU
Application.CreateForm (TfrmUnidadesPedidoVenta, frmUnidadesPedidoVenta);
frmUnidadesPedidoVenta.CarregaDades(Cantidad,UnitatsServidesBD);
frmUnidadesPedidoVenta.ShowModal;
varDades := frmUnidadesPedidoVenta.rebreDades;
varUnitatsRestants := frmUnidadesPedidoVenta.rebreUnitatsRestants;
freeandnil(frmUnidadesPedidoVenta);

try
cadenaSQL := 'SQL 1';
Ejecutar_SQL(cadenaSQL);
cadenaSQL := 'SQL 2';
Ejecutar_SQL(cadenaSQL);
query_supvision.Close;
query_supvision.Open;

except
showmessage('Error actualizando datos');
end;
end;
end
else if (FilaCheck = 'N') then
if (Cantidad = UnitatsServidesBD) then begin
botoseleccionat := MessageDlg('Estas seguro que quieres borrar las unidades servidas ?',mtCustom,[mbYes,mbNo], 0);
if botoseleccionat = mrYes then begin
cadenaSQL := 'SQL 1';
Ejecutar_SQL(cadenaSQL);

cadenaSQL := 'SQL2 ';
Ejecutar_SQL(cadenaSQL);
try
query_supvision.Close;
query_supvision.Open;
except
;
end
end
else begin
query_supvision.Cancel; // refrescar
end;
end;
end
else begin
showmessage('Este cliente no tiene más albaranes por editar');
query_supvision.Cancel; // refrescar
end;
if (combobox1.text = 'TODOS') then begin
try
query_supvision.Bookmark := Marca;
except
;
end;
end;
end;
end.

radge
24-07-2008, 12:38:16
Os muestro el codigo retocado , a ver si alguien consigue ver algo que ando "borracho" de tanto mirar el mismo formulario , aki os he dejado los cambios hechos , a ver si entre todos lo vemos.


muchas gracias , radge

coso
24-07-2008, 12:49:06
por ejemplo, aqui se crea, pero se libera correctamente? si no se hace, pasa lo mismo que antes...que se queda en memoria la anterior pues se usa la misma variable global para referenciarla.


procedure TfrmSupVision.BtnImprimirClick(Sender: TObject);
begin
Application.CreateForm (TfrmPrintPedidosSupervisados, frmPrintPedidosSupervisados);
frmPrintPedidosSupervisados.ShowModal;
end

coso
24-07-2008, 13:02:05
function tornarMaxID(): integer;
var cadenaSQLID : string;
query_maxID : TQuery;
begin
query_maxID := TQuery.Create(nil);
query_maxID.DatabaseName := Modulo_Datos.NOG_Comer.DatabaseName;
cadenaSQLID := 'SQLLLLLLLLLLLLLLL' ;
query_maxID.SQL.Clear;
query_maxID.close;
query_maxID.SQL.Add(cadenaSQLID);
query_maxID.open;
Result := query_maxID.Fields[0].Asinteger;
query_maxID.Close;
FreeAndNil(query_maxID);
end;


cadenaSQL := 'SQL 111111111';
Ejecutar_SQL(cadenaSQL);
cadenaSQL := 'SQL 2222222';
Ejecutar_SQL(cadenaSQL);

?, interpretais la sentencia sql? es bastante un nido de bugs esto radge :rolleyes:

(mejor del BookMarkStr, el getbookmark, gotobookmark y freebookmark)


Application.CreateForm (TfrmUnidadesPedidoVenta, frmUnidadesPedidoVenta);
frmUnidadesPedidoVenta.CarregaDades(Cantidad,UnitatsServidesBD);
frmUnidadesPedidoVenta.ShowModal;
varDades := frmUnidadesPedidoVenta.rebreDades;
varUnitatsRestants := frmUnidadesPedidoVenta.rebreUnitatsRestants;
freeandnil(frmUnidadesPedidoVenta);


lo mismo que antes, mejor usar tal cual la f, el f := TFrmunidadesPedidoventa.create, que sea f variable local, el f.free en vez del freeandnil etc...yo crearia todas las forms asi, tal como ya te habia comentado. El error fijo q esta por estas cosas, por crear todo con variables globales y luego volviendolo a crear con el mismo nombre de variables sin liberar las anteriores. saludos ; )

radge
24-07-2008, 15:16:45
Gracias sigo probando... una cosa tengo 2 problemas a ver si vosotros sabeis.

El 1º es que al debugar me salta dentro de las funciones nativas , eso debe ser alguna opcion que habilite y no recuerdo cual es.

La 2º duda k tengo es que ahora no me funciona lo siguiente : si selecciona una linea o texto , y le doy al suprimir o la tecla encima del return me "corre" las lineas pero no me las borra.

gracias radge

radge
25-07-2008, 16:15:25
por ejemplo, aqui se crea, pero se libera correctamente? si no se hace, pasa lo mismo que antes...que se queda en memoria la anterior pues se usa la misma variable global para referenciarla.

Código Delphi [-] (http://www.clubdelphi.com/foros/#)procedure TfrmSupVision.BtnImprimirClick(Sender: TObject); begin Application.CreateForm (TfrmPrintPedidosSupervisados, frmPrintPedidosSupervisados); frmPrintPedidosSupervisados.ShowModal; end




Esto es un boton que desde el form principal abre otro formulario , pero solo si lo llamo... que de momento esta deshabilitado asi k no creo que venga por aki , de todas formas el formulario lo tendria k destruir desde el mismo en el evento onclose no ?


Otra cosa... lo del famoso formulario

Application.CreateForm (TfrmUnidadesPedidoVenta, frmUnidadesPedidoVenta);
frmUnidadesPedidoVenta.enviarDadesSeguentForm(Cantidad,UnitatsServidesBD);
frmUnidadesPedidoVenta.ShowModal;
varDades := frmUnidadesPedidoVenta.rebreDades;
varUnitatsRestants := frmUnidadesPedidoVenta.rebreUnitatsRestants;
freeandnil(frmUnidadesPedidoVenta);


No creo que falle por aki , pk he borrado completamente estas lineas y sus referencias a el y sigue dando el mismo error.

Asi k seguimos buscando !

salu2 radge

coso
25-07-2008, 16:20:09
si, pero como te decia...si estas creando TODAS LAS FORMS de tu proyecto usando un solo nombre de variable para cada clase, sin liberar las anteriores y reusando ese nombre de variable, se te queda la anterior creada desreferenciada en memoria.

coso
25-07-2008, 16:21:59
Application.CreateForm (TfrmPrintPedidosSupervisados, frmPrintPedidosSupervisados); frmPrintPedidosSupervisados.ShowModal; end

de todas formas el formulario lo tendria k destruir desde el mismo en el evento onclose no ?

no, porque le estas asignando de parent la aplicacion, no la form que lo contiene, por eso lo del f:= Tform.Create(self)

radge
25-07-2008, 16:57:35
Lo siento llevo 2 semanas con delphi y no entiendo muy bien lo que dices.

Mira tengo la siguiente estructura

Formulario principal
frmMain
Formstyle : fsMDIForm


Desde el cual tengo un botton a frmsupvision con el siguiente codigo


procedure TfrmMain.BitBtn4Click(Sender: TObject); begin
WebBrowser1.SendToBack;
if not Assigned (frmSupVision) then
Application.CreateForm (TfrmSupVision, frmSupVision);
end;




Entonces abro el formulario supvision que tiene estas caracteristicas:
frmsupvision
formstyle : fsMDiChild


Y desde este si es necesario llamo a
frmUnidadespedidoVenta
formstyle : fsNormal

coso
25-07-2008, 17:44:02
El evento onclose de un form no destruye el formulario, solo lo cierra. Si tu destruyes un form, este destruye todos los componentes que la tienen en su propiedad parent.

lo que estas haciendo ahora mismo es esto:

f : objeto

...

f := crear_objeto;
f.Trabajamos
f.Cerramos (PERO NO DESTRUIMOS!)
...

y, al cabo de un rato, usando la misma variable

f := crear_objeto (*1)
f.Trabajamos
f.Cerramos (sin destruir otra vez)

si te fijas, en (*1) hemos perdido el valor anterior de f, el cual es un puntero a un objeto, y por lo tanto, tanto el puntero como el objeto quedan aun cargados y bloqueados en memoria, pero ya no se pueden localizar, por lo que tras sucesivas llamadas la memoria se te va a ir llenando hasta ya no poder cargar nada mas. Imagina que en la primera asignacion f fuese 0x00100 ocupando 200; en la segunda vuelta ponemos a f := 0x00300 ocupando 200 mas: la direccion de 0x00100 a 0x00300 se nos queda bloqueada y peor aun, sin poder acceder a ella. Vamos, que nos quedamos sin memoria. Por eso te salta a las 30 o 40 veces. Mira, cuando te salte el error, el administrador de tareas cuanta memoria estas consumiendo, o bien un administrador de memoria (por internet los hay de buenos). La gracia de las variables locales es precisamente que tienes controlado cuando las llamas y cuando las destruyes: solo usaras ese nombre mientras este usandose la form, y nadie mas en el programa la usaria. Si son forms de las que solo necesitas una instancia a la vez, lo mejor es usar el autocreate y llamarlas directamente con el showmodal, olvidandote de crear de nuevas en todo el proyecto: creas todas las del proyecto que seguro necesites y las llamas. Las que no, las creas LOCALMENTE, usas, y destruyes tambien localmente. Lo de TForm1.Create(parent) es para q cuando se destruya el parent, tambien se destruya el objeto creado.

otro ejemplo : en un proyecto tengo dos classes, TForm1, TForm2 con dos instancias con el autocreate : Form1, Form2. Imagina que en el form1 hay 2 botones.



procedure TForm1.ButtonClick(sender : TObject);
var
f1 : TForm1;
f2 : TForm2;
begin
f1 := TForm1.Create(self);
f1.ShowModal;
f1.Free;
f2 := TForm2.Create(self);
f2.ShowModal;
f2.Free;
end;

procedure TForm1.Button2Click(sender : TObject);
begin
Form1 := TForm1.Create(self);
Form1.ShowModal;

Form2 := TForm2.Create(self);
Form2.ShowModal;
end;



pruebalo, veras que los 2 parece que funcionan igual, pero no. Puesto que tal como te habia dicho, en el segundo estamos sobreescribiendo las variables globales Form1 y Form2 con nuevos objetos tipo TForm1,TForm2, perdiendo los anteriores por memoria, mientras que en el primero estamos creando nuevas instancias sin perder sus referencias. En el caso de poner Form1.Free, Form2.Free despues del showmodal, tendras el inconveniente de eliminar todas las instancias (aunque no se liberarian las forms anteriores, pues se quedaron desreferenciadas) que hay en el proyecto. En tu caso, seria lo correcto, siempre que no se llamen ni a ninguna propiedad ni funcion sin crearlas anteriormente, vamos, siempre que no estes usando la variable global sin crearla anteriormente.

radge
28-07-2008, 08:19:19
He probado lo siguiente ya os comentaré si falla o no.


procedure TfrmSupVision.wwDBGrid1FieldChanged(Sender: TObject; Field: TField);
Var formulari : TfrmUnidadesPedidoVenta;
begin
formulari := TfrmUnidadesPedidoVenta.Create(self);
formulari.CarregaDades(Cantidad,UnitatsServidesBD);
formulari.ShowModal;
varDades := formulari.rebreDades;
varUnitatsRestants := formulari.rebreUnitatsRestants;
formulari.Free;




Lo que si que me salen son muchos errores de escritura.

http://img73.imageshack.us/img73/8809/deleteradgecd7.jpg (http://imageshack.us)
http://img73.imageshack.us/img73/8809/deleteradgecd7.63d3f2473b.jpg (http://g.imageshack.us/g.php?h=73&i=deleteradgecd7.jpg)

radge
26-08-2008, 15:43:04
Os vuelvo a dejar el codigo con los cambios descritos arriba por el compañero , sigue fallando ;(

de todas formas gracias



procedure TfrmSupVision.wwDBGrid1FieldChanged(Sender: TObject;
Field: TField);
Var
Qry: TQuery;
cadenaSQL,FilaCheck,Lin_Codi,Alb_Codi,Per_Codi,accountnum,dataareaid ,
varDades , varUnitatsRestants : string;
Cantidad , UnitatsServidesBD , botoseleccionat : Integer ;
Marca : TBookMarkStr;
formulari : TfrmUnidadesPedidoVenta;
begin
try
Lin_Codi := query_supvision.FieldbyName('LIN_Codi').AsString;
...
...
except
showmessage('No se han podido cargar los datos del albarán');
query_supvision.close;
query_supvision.open;
end;
if not assigned (Qry) then begin
Qry := TQuery.Create (nil);
Qry.DatabaseName := Modulo_Datos.NOG_Comer.DatabaseName;
end;
Qry.Close;
Qry.SQL.Clear;

if ((Lin_Codi <> '') and (Dataareaid <> '') and (Alb_Codi <> '') and (Per_Codi <> '') and (Accountnum <> '')) then begin
if (cmbSupervisado.text = 'TODOS') then begin
try
Marca := query_supvision.Bookmark;
except
query_supvision.close;
query_supvision.open;
end;
end;
try
FilaCheck := wwDBGrid1.GetFieldValue(7); // Si cambiem l'ordre del grid cambiar el GetFieldValue
except
showmessage('Hubo un error cargando los datos del formulario');
query_supvision.close;
query_supvision.open;
end;

if (FilaCheck = 'S') then begin
// 1 unitat , fiquem la data i l'introduim a la BD
if (Cantidad = 1) then begin
Qry.SQL.Clear;
cadenaSQL := 'update tabla .................';
Qry.SQL.Add(cadenaSQL);
Qry.ExecSQL;

Qry.SQL.Clear;
cadenaSQL := 'Insert into tabla ............';
Qry.SQL.Add(cadenaSQL);
Qry.ExecSQL;

query_supvision.close;
query_supvision.Open;
end
else begin
formulari := TfrmUnidadesPedidoVenta.Create(self);
formulari.CarregaDades(Cantidad,UnitatsServidesBD);
formulari.ShowModal;
varDades := formulari.rebreDades;
varUnitatsRestants := formulari.rebreUnitatsRestants;
if assigned(formulari) then
freeandnil(formulari);

Qry.SQL.Clear;
cadenaSQL := 'update tabla .........';
Qry.SQL.Add(cadenaSQL);
Qry.ExecSQL;

Qry.SQL.Clear;
cadenaSQL := 'Insert into .................';
Qry.SQL.Add(cadenaSQL);
Qry.ExecSQL;

query_supvision.Close;
query_supvision.Open;
end;
end
else if (FilaCheck = 'N') then
if (Cantidad = UnitatsServidesBD) then begin
// procedim a desmarcar
botoseleccionat := MessageDlg('Estas seguro que quieres borrar las unidades servidas ?',mtCustom,[mbYes,mbNo], 0);
if botoseleccionat = mrYes then begin
Qry.SQL.Clear;
cadenaSQL := 'update tabla .............. ';
Qry.SQL.Add(cadenaSQL);
Qry.ExecSQL;

Qry.SQL.Clear;
cadenaSQL := 'update table .............. ';
Qry.SQL.Add(cadenaSQL);
Qry.ExecSQL;

query_supvision.Close;
query_supvision.Open;
end
else begin
query_supvision.cancel;
end;
end;
end
else begin
showmessage('Este cliente no tiene más albaranes por editar');
try
query_supvision.Close;
query_supvision.open;
except
;
end;
end;
if (cmbSupervisado.text = 'TODOS') then begin
try
query_supvision.Bookmark := Marca;
except
query_supvision.close;
query_supvision.open;
end;
end;
end;
end.