Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Raised Exception (https://www.clubdelphi.com/foros/showthread.php?t=3303)

javiermorales 01-09-2003 21:52:42

Raised Exception
 
Buenas Tardes, se me produce el siguiente error:

"Project SIGECO.exe raised exception class EAccessViolation with message 'Violación de acceso en la dirección 00503A36 en módulo 'SIGECO.EXE'. Leer de dirección 'FFFFFFFF'. Process stopped. Use Step or Run to continue"

Le he realizado una traza y no indica el punto exacto del código donde se produce el error, pero ocurre en todos los formularios que cierro a través de código. Dichos formularios se han creado utilizando el siguiente código:

Código:

Application.CreateForm(TFormClass(listaclass[i]),Pantalla[j]);
IndicePantalla := j;
Pantalla[j].Show;

Por su puesto es mucho más largo, pero en concreto este es el momento en que se crea el formulario y no dá ningún problema. Para cerrar dicho formulario, realizo lo siguiente

Código:

  Pantalla[i].Close;
  Pantalla[i].Free;
  Pantalla[i] := nil;

Teniendo en cuenta que el valor de i se le pasa en el momento de la creación del formulario.

Se produce el error, se acepta el mensaje y todo continua,pero claro los usuarios se preocupan y da una imagen muy pobre de la aplicación

Será muy bienvenida cualquier sugerencia. Gracias a todos. Un saludo.

delphi.com.ar 01-09-2003 22:26:13

¿Lo has ejecutado paso a paso y verificado si i tiene el valor que tu crees que tiene?

sanxpue 01-09-2003 23:09:23

tambien pasa cuando remueves las formas del proyecto..

si es que las removiste debes de usar el showmodal y no nada mas show..

saludos desde Puebla Mexico
asanxt@hotmail.com

Julià T. 02-09-2003 02:19:03

Cita:

'Violación de acceso en la dirección 00503A36 en módulo 'SIGECO.EXE'. Leer de dirección 'FFFFFFFF'. Process stopped. Use Step or Run to continue
Violación de acceso suele ocurrir cuando intentas acceder a una parte de un array que no está accesible Ej: intentas acceder al myarray[7] cuando tan solo tienes hasta myarray[6]

El error FFFFFFFF aparece cuando intentamos acceder a una clase que no se ha creado (falta la línea "myclass.create(parametros)")

Espero que se entienda

javiermorales 02-09-2003 08:34:14

Muchas gracias por vuestras contestaciones, voy a verificar que el item del array al que intento acceder no es nulo y que el indice del mismo es exactamente al que se supone debo acceder.

Cuando tenga los resultados os los hare llegar. Gracias de nuevo.

javiermorales 04-09-2003 23:54:31

Hola a todos, ya he verificado que el indice del array es el correcto y que el valor de ese item no es NULL y es accesible.

Realizando la traza, no se detiene en ninguna línea de codigo, sino que tras terminar el código que debe ejecutar, saca el error, sin realizar parada en línea alguna.

Si se os osurre alguna cosa más que verificar será muy bién venida. Gracias, un saludo.

Julià T. 05-09-2003 00:20:32

Vuelvo a mirar el código que pones y me he dado cuenta de que:

el close, Free, nil, lo deberias poner en la ventana que utilizas con el Show, no en la que lo llama, más o menos así:

procedure Tform1.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
action:=cafree;
end;

si fuera Showmodal si que podrias realizarlo con el código que escribes.

javiermorales 05-09-2003 08:43:23

Es cierto, debería haber puesto el código cmpleto, ya que en realidad, hace lo siguiente:

Código:

Pantalla[i].Close;
if (Pantalla[i] <> NULL) then
begin
  Pantalla[i].Free;
  Pantalla[i] := nil;
end;

Y en el Close del Formulario es donde se realiza el Free y nil. He dejado esa parte aquí, por si por algún error no realizaba la liberación en el formulario, aunque trazándolo nunca llega a ejecutar la parte del condicional, puesto que lo ha liberado antes.

Gracias por contestar.

Julià T. 06-09-2003 04:29:12

Si utilizas un showmodal, el código de la función se detine en ese punto, en cambio si utilizas show no, por lo que el código sigue y se libera el form, con lo que o no lo puedes utilizar o no tiene tiempo a ejecutar el código y da errorres como los que te da

ejempo código con showmodal

Tform1.funcion1
begin
Form2:=Tform2.Create(self);
Form2.Showmodal;
Form2.free;
end;

ejempo código con showmodal
Tform1.funcion1
begin
Form2:=Tform2.Create(self);
Form2.Show;
//no hay free
end;

Tform2.Close .....
begin
action:=caFree;
end;

Julià T. 06-09-2003 04:36:29

perdona las prisa, corrigo el anterior

Si utilizas un showmodal, el código de la función se detine en ese punto, en cambio si utilizas show no, por lo que el código sigue y se libera el form, con lo que o no lo puedes utilizar o no tiene tiempo a ejecutar el código y da errorres como los que te da

Código:

ejempo código con showmodal
Tform1.funcion1
begin
Form2:=Tform2.Create(self);
Form2.Showmodal;
Form2.free;
end;

Código:

ejempo código con show
Tform1.funcion1
begin
Form2:=Tform2.Create(self);
Form2.Show;
//no hay free se debe liberar en el propio formulario
end;


Tform2.Close .....
begin
action:=caFree;
end;


javiermorales 06-09-2003 11:22:21

Gracias Julia.T por responder. Te comento un poco más el funcionamiento que tiene la aplicación:

Desde la pantalla principal, que nunca se cierra salvo para finalizar la aplicación, es donde se construyen los formularios, cuando se selecciona la opción de menu, que a su vez construyo dinamicamente basándome en la base de datos donde están las autorizaciones que tenga cada usuario, así como las opciones de menú asociadas y el nombre de cada uno de los formularios que se deben lanzar.

Se utiliza Show y no Showmodal, por que no es el formulario padre quien libera al formulario, sino que en módulo aparte es donde tengo el procedimiento de liberación. Además si utilizase ShowModal, quedaría restringida la utilización de opciones de menú diferentes al mismo tiempo (sabemos que eso no es posible, pero sí podemos ir cambiando de formulario en la ejecución)

Es decir el main crea la clase y lanza el formulario, asignando a un array global de clases el formulario creado. El formulario creado puede terminar su ejecución de dos maneras:

1.- Haciendo click en la cruz superio derecha, con lo que se llama al evento close del formulario:
Código:

Procedimiento Close del formulario
  Pantalla[i].Free;
  Pantalla[i] := nil;

2.- Pulsando la tecla ESC, que esta reprogramada, para llamar a un procedimiento global de liberación:
Código:

Procedimiento Global de Liberación
Pantalla[i].Close;
if (Pantalla[i] <> NULL) then//No se ejecuta Nunca
begin
  Pantalla[i].Free;
  Pantalla[i] := nil;
end;

El error me lo da al utilizar la tecla reprogramada, pero no en ninguna de las líneas de código, sino al termimar de ejecutar todo el código. Realizando las comprobaciones, el formulario se libera y todo funciona correctamente, pero le salta ese error al usuario y no queda demasiado bién.

Muchas Gracias de nuevo Julia, espero haberme explicado un poco mejor esta vez. Un saludo

Julià T. 06-09-2003 14:56:07

¡Entendido!

Me pasó lo mismo en un programa que hize en Delphi 2, ya hace mucho, lo solucioné colocando un manipulador de exepciones global y acallando el error (creo que luego colocando el Action:=caFree en el onclose dejó de hacerlo, y creo que es por eso que siempre coloco este código en los close).

Si estamos en Delphi 5 o superior existe un componente llamado ApplicationEvents en la paleta addictional que tiene un evento llamado onException. Tan solo nos hará falta colocar algo de código
Código:

procedure TForm1.ApplicationEvents1Exception(Sender: TObject;
  E: Exception);
begin
//
end;

para que cuando ocurra no aparezca el error.

el ApplicationEvents lo deberás colocar el la ventana que se produce el error, sea la principal u otra.

Si tienes delphi 4 o inferior, deberia recuperar el programa, para acordarme de como lo hacia.

Espero que esto si te sirva finalmente

Mick 06-09-2003 22:01:36

Ocultar la excepcion no es una solucion, es un gravisimo error :(, porque el bug en el programa sigue existiendo, es como si para parar una epidemia los medicos decidiesen ocultar los cadáveres para que "no se note" ;).

Si se produce una excepcion
de ese tipo, es posible que alguna parte del programa (variables por ejemplo) se machaquen al azar, o que otros objetos no hayan podido ser destruidos porque una excepcion hace que la ejecucion del programa se interrumpa bruscamente en algun punto.

De modo que a partir de una excepcion de ese tipo cualquier programa quedara en un estado "inestable" no se puede garantizar que siga funcionando correctamente o (lo que es peor) que los resultados que de sean correctos, hasta que se cierre y se vuelva a ejecutar.

Salud2 !!!

Julià T. 07-09-2003 03:55:28

por cierto al puslar la tecla esc se finaliza todo el código tipo

tecla=esc =>
begin
Close;
exit;
end;

o bien queda algo colcago por finalizar

tecla=esc =>
begin
Close;
end;
.... continua el código

javiermorales 07-09-2003 11:32:27

Hola Juliá, este es el código del KeyDown donde se trata la tecla ESC:
Código:

  //Pulsacion de Cancelar (ESC)
  if (Key=VK_ESCAPE) then
  begin
    if not(DataSource3.DataSet.State in [dsInsert,dsEdit]) then
    begin
      Key := 0;
      LiberaPantalla(numpantalla);
    end
    else
      DBEdit18.SetFocus;
    Exit;
  end;

Está hecho de esta manera, para que cuando tenga el DataSource en edición, el Escape tenga su funcionalidad por defecto, es decir deshacer el último cambio. Y lo hace correctamente.

Tiene el Exit al final, porque dentro del KeyDown trato muchas mas teclas y como no puedo utilizar un Case, me veo obligado a hacerlo con if...else. Por eso pongo el Exit, para que no continue con los if...else.

¿Comentas lo del código al final, porque intentaría ejecutar el Exit sobre algo que ya no existe?.

Gracias. Un saludo.

Julià T. 07-09-2003 14:44:22

intenta colocar el exit dentro de la condición aunque creo que no soluciones nada

if (Key=VK_ESCAPE) then
begin
if not(DataSource3.DataSet.State in [dsInsert,dsEdit]) then
begin
Key := 0;
LiberaPantalla(numpantalla);
exit;
end

luego te envio el código que utilizo yo para crear y cerrar una ventana no modal desde otra

Julià T. 07-09-2003 15:47:03

Te muestro el código que utilizo para mostrar los informes de manera no modal y cerrarlos desde una ventana que no es la propia.

El inconveninete que tiene es que de esta manera no se puede acceder a ningun valor ni funcion de la ventana (solo mostrar y cerrar)

Código:

type
  TInformes = class(TForm)
  ...
  public
    class procedure Mostrar(ATag: integer);
    class procedure Tancar;
  end;

Var
 VTag:integer;

class procedure TInformes.Mostrar(ATag:integer);
Var
 I:integer;
 F:Tform;
begin
  For I:=Screen.FormCount-1 downto 0 do
  begin
  F:=Screen.Forms[i];
  if (F is Self) and(Atag<>0) then
    begin
    if (F.Tag=Atag) or (F.Tag+1000=Atag) then
    begin
      f.show;
      F.BringToFront;
      exit;
    end;
  end;
  end;
  VTag:=ATag;
  F:=Create(Application);
  F.FormStyle:=fsMDIChild;
  F.WindowState:=wsMaximized;
  F.BringToFront;
end;

class procedure TInformes.Tancar;
Var
 I:integer;
 F:Tform;
begin
  For I:=Screen.FormCount-1 downto 0 do
  begin
  F:=Screen.Forms[i];
  if (F is Self) then F.Close;  //and tag=num
  end;
end;


javiermorales 07-09-2003 18:32:10

Hola Julià, muchas gracias por tu última respuesta y por el código. Resulta que es bastante similar a como lo hago yo. Te lo adjunto:
1.- Código de creación de Forms
Código:

procedure TMainForm.AbrirForm();
var
  i, j : integer;
  a : boolean;
begin
 i := 0;
 j := 1;
 a := true;
 while (a) do
 begin
  if (Screen.Forms[i].Name = PDatItem(TreeView1.Selected.data)
      ^.Pantalla) then
    a := false
  else
  begin
    if (i < (Screen.FormCount - 1)) then
      i := i+1
    else
    begin
      a := false;
      i := 1000;
    end
  end
 end;
 if (i < 1000) then
  Screen.Forms[i].Show
 else
 begin
  i := 0;
  While (i < listaclass.Count) and (listaclass[i].ClassName <>
              PDatItem(TreeView1.Selected.data)^.TPantalla) do
        inc(i);
  if (i < listaclass.Count) then //hemos encontrado la clase
  begin
    While (Pantalla[j] <> nil) and (j <= 25) do
      inc(j);
    Application.CreateForm(TFormClass(listaclass[i]),Pantalla[j]);
    IndicePantalla := j;
    Pantalla[j].Show;
  end
 end
end;

El código de cierre de formularios, lo he puesto en otra de las respuestas.

Gracias Julià, si le vieses algo al código, por favor coméntamelo.
Un saludo.
E

Julià T. 08-09-2003 02:35:03

Hola:

He rehecho el código para ir deprisa he hecho mi propia adaptación, me funciona correctamente.

Código:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Controls, Forms, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    Index:integer;
    listaclass:array[1..10] of TFormclass;
    listpant:array[1..10] of TForm;
    function Existe(Nombre: string): boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Unit2, Unit3;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
//relleno los arrays con los forms y TForm
//creo que en tu caso son diferentes
 listaclass[1]:=TForm2;
 listaclass[2]:=TForm3;
 listpant[1]:=Form2;
 listpant[2]:=Form3;
end;

function TForm1.Existe(Nombre:string):boolean;
Var
 i:integer;
begin
 //busca en las ventanas creadas si existe la muestra
 Result:=False;
 For I:=Screen.FormCount-1 downto 0 do
  if Screen.Forms[i].Name = Nombre then
  begin
    Result:=True;
    Screen.Forms[i].Show;
    break;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
  Nombre:string;
begin
 //muestra o crea la ventana con el nomre indicado en el edit1.text
 Nombre:=Edit1.text;
 if Existe(Nombre) then exit;
 For i:=Low(listaclass) to High(listaclass) do
 begin
  if Assigned(listaclass[i]) and (listaclass[i].ClassName='T'+Nombre) then
  begin
    Application.CreateForm(listaclass[i],listpant[i]);
//  listpant[i]:=listaclass[i].Create(Self);  //no hay problema también sirve
  Index := i;
  listpant[Index].Show;
  end;
 end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 //esto cierra la última que has abierto sólo la última
 if Assigned(listpant[Index]) then FreeAndNil(listPant[Index]);
//if Assigned(listpant[Index]) then  listpant[Index].Close;  //no hay problema también sirve
//prefiero el close
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  i: integer;
  Nombre:string;
begin
 //Cierra la ventana indicada en el Edit1.text
 Nombre:=Edit1.text;
 For I:=Screen.FormCount-1 downto 0 do
  if Screen.Forms[i].Name = Nombre then Screen.Forms[i].Close;
end;

end.


javiermorales 08-09-2003 12:51:48

Muchas Gracias Julià. Voy a intentar adaptar el código que me has pasado a mi aplicación. En cuanto tenga los resultados te los comento.

Gracias de nuevo. Un abrazo.


La franja horaria es GMT +2. Ahora son las 23:10:23.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi