tratamento de erros/exceções não funciona

03/02/2006

Prezados colegas:

Creio que já mencionei que tenho pouquíssima experiência em Delphi mas, ainda assim, estou obtendo razoáveis progressos em razão de meus (parcos) conhecimentos em outras linguagens de programação e, principalmente, de minhas fontes de consultas, entre elas este fórum. Portanto, peço mais uma vez o auxílio dos colegas a fim de que me esclareçam outra dúvida, um tanto banal (como sempre), mas que nem livros, nem as soluções aqui apresentadas puderam resolver.
Antes de mais nada, esclareço que minha aplicação aparentemente funciona com perfeição. Ocorre que tentei implementar tratamento de exceções em alguns procedimentos, a princípio utilizando a estrutura try...except para capturar os erros. Pois bem, mesmo provocando-os de maneira deliberada (como os que envolvem divisões por zero), NENHUMA MENSAGEM surgia. Cheguei a desconfiar que, por algum motivo, o código estaria sendo desviado antes do término da rotina, mas certifiquei que isso não ocorria após envolver sua execução com ´flags´ (na verdade, um punhado de ShowMessages).
Em seguida, decidi utilizar a estrutura try...finally. Agora, as mensagens surgem em QUALQUER CHAMADA de procedimento que possua tal implementação, ainda que todas as operações sejam executadas de maneira correta.
Pesquisei dezenas de soluções apresentadas pelos colegas e quase todas sugerem aquilo que eu já vinha utilizando. Como última alternativa, inseri um componente ´ApplicationEvents´ no formulário principal, mas não resolveu o problema, pois também não acusou qualquer erro, seja ele provocado entre uma instrução try...except, try...finally ou fora delas (o que seria a sua finalidade). Numa das soluções pesquisadas, porém, um colega chegou a recomendar que tratamentos de erros devem ser testados ´fora do ambiente Delphi´. Um outro afirmou que, em determinadas circunstâncias, tais rotinas simplesmente ´não funcionariam´. Alguém poderia me explicar o que acontece? Desde já, agradeço a atenção dispensada.
OBS: utilizo a versão 6.0 do Delphi.


Spiritwwwalker

Respostas

03/02/2006

Emerson

coloque isso num botão para testar:

a := 12; // integer
b := ´teste´; // string
c := 0; // double
try
  c := a + strtoint(b);
  showmessage(´Tudo certo!´);
except
  showmessage(´Erro nos valores informados!´);
  //essa msg deve aparecer porque o sistema
  //não conseguirá converter ´´ para um inteiro
end;


se a mensagem aparecer, peço que você publique aqui um trecho do seu código para que possamos analisar.


Responder Citar

03/02/2006

Massuda

try..except e try..finally possuem uma diferença.

O código no except..end só é executado em caso de exceção. Já o código no finally..end é executado sempre. No primeiro você deve pôr código para tratar a exceção e no segundo, código que deve ser sempre executado, não importa o que aconteça.

No caso do try..except, você pode definir vários on...do, cada um para um tipo diferente de exceção. Por exemplo...
try
  .... faz alguma coisa ....
except
  on E: ERangeError do
    // trata erro de fora de faixa
  on E: EAlgumaExcecao do
    // trata outra exceção
  on E: Exception
    // trata qualquer erro que não tratamos antes
end;

Outra coisa: na IDE do Delphi existe uma opção para sempre parar a execução do programa em caso de exceção (mesmo tendo os try..except/finally). Isso é controlado pela opção [b:b69110a027]Stop on Delphi Exceptions[/b:b69110a027] que está em [b:b69110a027]Tools|Debugger options|Language exceptions[/b:b69110a027] (talvez o menu possa ser diferente dependendo da versão de Delphi que você usa)


Responder Citar

03/02/2006

Truck1n

Try ... Except ... end;

é tratamento de erros.

Try ... Finally ... end;

Proteção de recursos

 
a: Integer;

Try 
   a := ´Truck1n´;
except
   ShowMessage(´Um Inteiro nao pode receber uma String´);
End;

********

Try
   Form1 := Tfom1.create(application);
finally
   Form1.Show;
End;  




Responder Citar

04/02/2006

Spiritwwwalker

Caros colegas:

Gostaria que desculpassem minha ignorância. Digo isso porque, se a estrutura try..finally tem a execução garantida, se eu implementar uma mensagem de erro personalizada após finally (ainda que a exceção não exista), a mensagem irá aparecer SEMPRE... Por outro lado, a estrutura try...except continua sem efeito, mesmo provocando exceções de maneira deliberada. Observem:



Prezado emerson.en:

Segui suas instruções e, ao clicar no botão de comando, minha máquina travou de maneira espetacular. Você devia ter visto: precisei utilizar o botão reset (risos). Abaixo, segue um trecho implementado logo no evento OnShow do formulário (a primeira e a última mensagens são exibidas, mas a segunda é solenemente ignorada):

procedure TFormTeste.FormShow(Sender: TObject);
var x, y : integer;
begin
try
y := 0;
x := 3 div y;
ShowMessage(´Vai ocorrer um erro.´);
except
ShowMessage(´Erro de divisão por zero.´);
end;
ShowMessage(´Erro não detectado.´);
end;



Prezado Massuda:

Também segui sua dica no sentido de examinar as configurações de ´Debugger Options´. Na guia ´Language Exceptions´, encontrei ´Exceptions Types to Ignore´:
Delphi EAbort Exceptions
Microsoft DAO Exceptions
VisiBroker Internal Exceptions
CORBA System Exceptions
CORBA User Exceptions
As quatro primeiras estavam selecionadas. Mais abaixo (e também selecionada) estava ´Stop on Delphi Exceptions´. Fiz alguns testes desativando algumas opções, mas o resultado continuou o mesmo, isto é, a estrutura try..except está inerte (mesmo eu provocando as exceções). O que pode ser? Grato pela atenção.



Prezado Truck1nl:

Obrigado pelas orientações. Como eu disse acima, descobri a causa das irritantes mensagens empregando try..finally. O código executava o que eu mesmo havia determinado (risos), contudo a estrutura try..except continua apresentando problemas. Se puder me ajudar mais uma vez, agradeceria muito.


Responder Citar

04/02/2006

Emerson

fiz o teste aqui com o exemplo que você passou (utilizo D7) e ocorreu o esperado: a mensagem de erro avisando sobre a divisão por zero.

não sei te dizer o que pode estar ocorrendo.


Responder Citar

04/02/2006

Marco Salles

Deixe eu participar um pouquinho desta calorosa discusão

[color=darkred:defea7f8b3]O código que voce postou não vale para Exemplo[/color:defea7f8b3]

var x, y : integer; 
begin 
try 
y := 0; 
x := 3 div y; 
ShowMessage(´Vai ocorrer um erro.´); 
except 
ShowMessage(´Erro de divisão por zero.´); 
end; 
ShowMessage(´Erro não detectado.´); 
end; 


[color=blue:defea7f8b3][b:defea7f8b3]Não vale porque o compilador ignora simplesmente as instruçoes[/b:defea7f8b3][/color:defea7f8b3]
[b:defea7f8b3]y := 0;
x := 3 div y; [/b:defea7f8b3]

[color=darkblue:defea7f8b3][b:defea7f8b3]Ele ignora estas linhas devido ao falto de não usa-las [/b:defea7f8b3][/color:defea7f8b3]...Este é um recurso do compilador e ja foi outrora discudido aqui no Forum

:arrow: :arrow:
[b:defea7f8b3]Para provocar o erro[/b:defea7f8b3] , voce deve utilizar o conteudo destas variáveis.. No caso a variável X

:cry: :cry:
Percebo ainda que falta a estrutura citada pelo massuda

No caso do try..except, você pode definir vários on...do, cada um para um tipo diferente de exceção. Por exemplo...


que no seu caso e especificamente o erro é [color=darkred:defea7f8b3][b:defea7f8b3]EDivByZero[/b:defea7f8b3][/color:defea7f8b3]

Corrigindo seria isto :

procedure TForm1.FormShow(Sender: TObject);
var x, y : integer;
begin
try
y := 0;
x := 3 div y;
showmessage(inttostr(x));
ShowMessage(´Vai ocorrer um erro. Mas esta mensagem não ira aparecer´);
except
on  E: ERangeError do
  showmessage(´Esta mensagem não ira aparecer pois o erro não é deste tipo´);
on E:EdivByZero do
 ShowMessage(´Erro de divisão por zero.´);
end;
ShowMessage(´Erro não detectado.´);
end;


[color=blue:defea7f8b3][b:defea7f8b3]Mas ainda tem o Finally [/b:defea7f8b3][/color:defea7f8b3], que não so pode , como deve ser sempre implementado , pois recomenda-sse algumas biografias que a inclusão do mesmo , evita o vazamento de recurso ou de memória

Ficando assim :

procedure TForm1.FormShow(Sender: TObject);
var x, y : integer;
erro:Boolean;
begin
  try
    try
      erro:=false;
      y := 0;
      x := 3 div y;
      showmessage(inttostr(x));
      ShowMessage(´Vai ocorrer um erro. Mas esta mensagem não ira aparecer´);
   except
       on  E: ERangeError do
         begin
         erro:=True;
         showmessage(´Esta mensagem não ira aparecer pois o erro não é deste tipo´);
         end;
       on E:EdivByZero do
         begin
           erro:=True;
           ShowMessage(´Erro de divisão por zero.´);
         end;
   end;
 finally //sempre sera executado. Ocorrendo um erro ou Não
   if erro Then
    showmessage(´Erro Detectado´)
   else
    ShowMessage(´Erro não detectado.´);
 end;
end;


:?: :?: :?:
Agora tem que ver por fim , nestas indas e vindas o que voce fez com o IDE do delphi...


Responder Citar

04/02/2006

Emerson

[quote:09dd8da70c=´Marco Salles´]Deixe eu participar um pouquinho desta calorosa discusão

[color=darkred:09dd8da70c]O código que voce postou não vale para Exemplo[/color:09dd8da70c][/quote:09dd8da70c]eu usei exatamente aquele código postado, Marco. e funcionou perfeitamente. eu também pensei que não funcionou pro SpiritWWWalker por conta de a variável não ter sido aproveitada no código. mas na minha máquina funcionou perfeitamente, mesmo eu não utlizando a variável.
prova disso é que este código abaixo funciona perfeitamente:
try
  strtoint(´a´);
except
  showmessage(´erro ao converter valor´)
end;

não tem qualquer variável, não uso o retorno de strtoint() e mesmo assim a mensagem do except é exibida.


Responder Citar

04/02/2006

Marco Salles

eu usei exatamente aquele código postado, Marco. e funcionou perfeitamente. eu também pensei que não funcionou pro SpiritWWWalker por conta de a variável não ter sido aproveitada no código.


e , sua máquina não esta de acordo com a minha ultimamente.. Mas acho que a regra é não funcionar . Pelo fato da variável não ser aproveitada

[color=darkred:ee1ab71eca]Mas o exemplo que voce deu :[/color:ee1ab71eca]

try strtoint(´a´); except showmessage(´erro ao converter valor´) end;


não tem qualquer variável, não uso o retorno de strtoint() e mesmo assim a mensagem do except é exibida.


[color=darkblue:ee1ab71eca]O Erro ira aparecer[/color:ee1ab71eca] , :arrow: porque o compilador compila estas isntruçoes.. [b:ee1ab71eca]Aqui tb deu erro neste caso e no primeiro caso não deu.[/b:ee1ab71eca].. Verifique por gentileza se o seu compilador esta compilando as instruçoes
[b:ee1ab71eca]y := 0;
x := 3 div y; [/b:ee1ab71eca]
se estiver compilando , talves seje uma nova versão ou ou configuração alterada da IDE

e outra talvez voce não tenha entendido que o SpiritWWWalker quer que apareça a mensagem
[b:ee1ab71eca]ShowMessage(´Erro de divisão por zero.´); [/b:ee1ab71eca] e não esta
[b:ee1ab71eca]ShowMessage(´Vai ocorrer um erro.´); [/b:ee1ab71eca]


Responder Citar

04/02/2006

Emerson

rapaz... comigo funcionou das duas formas... eu tenho o Delphi 7 instalado sem qualquer alteração na IDE. a única coisa alterada na configuração é o fato de eu ter desmarcado a opção [i:fbf3451b17]Stop on Delphi exceptions[/i:fbf3451b17], pois eu sempre trato minhas exceções e não preciso dela marcada.


Responder Citar

04/02/2006

Marco Salles

a única coisa alterada na configuração é o fato de eu ter desmarcado a opção Stop on Delphi exceptions


Isto acho que so influencia na opção do delphi mostrar ou não a mensagem de erro , quando se esta executando via projeto

Com a opção marcada o Delphi mostra o erro e depois a mensagem tratada
Com a opção desmarcada o delphi não mostra o erro e a aparece somente a mensagem ´Tratada´

Mas me incuca o fato de voce dizer que funcionou :?: :?: :?:

[b:91bf029348]Mas uma vez eu pergunto..[/b:91bf029348]

[b:91bf029348][color=darkred:91bf029348]Verifique por gentileza se o seu compilador esta compilando as instruçoes
y := 0;
x := 3 div y;[/color:91bf029348] [/b:91bf029348]

:!: :!: :!:
Marque de vermelho uma intrução anterior a esta, rode por F9 e verifique se estas duas instruçoes forem Grivadas de Azul antes da execução propriamente dita do programa

procedure TFormTeste.FormShow(Sender: TObject); 
var x, y : integer; 
begin 
try //marque esta opçaõ de vermelho
y := 0; //verifique se esta linha esta marcada de azul ao rodar o programa via F9
x := 3 div y;// verifique se esta linha tb esta marcada de azul 
ShowMessage(´Vai ocorrer um erro.´); 
except 
ShowMessage(´Erro de divisão por zero.´); 
end; 
ShowMessage(´Erro não detectado.´); 
end; 


Não é possivel :?: :?: :?: :?: :?:


Responder Citar

04/02/2006

Spiritwwwalker

Prezados colegas:

Segui as instruções do colega Marcos Salles, implementado o código que sugeriu no evento OnShow do formulário. O resultado: um travamento que obrigou-me a um reset (risos). Quanto ao meu exemplo, procurei torna-lo o mais simples possível para exemplificar uma anomalia irritante. Já tinha conhecimento do tratamento de exceções específicas, como os de divisão por zero (EdivByZero), já tendo efetuado testes com códigos similares aos seus. Talvez o colega Marcos tenha razão em afirmar que o modelo proposto não seja válido como exemplo, já que a variável não foi efetivamente utilizada; por outro lado, o CÁLCULO matemático FOI FEITO ou, ao menos tentado, e presume-se que isso seria suficiente para uma manifestação de erro. Prova disso, é o colega emerson.en, bem como de outras sugestões propostas em outros tópicos que abordam o mesmo assunto. Ademais, também já havia tentado exibir o valor da variável ´´x´ para saber se ela fora inicializada (se bem me recordo, isso igualmente ocasionou o travamento da máquina). Creio que essas diferenças devem variar de uma versão do Delphi para outra (original ou made in Coreano da Paulista), bem como as configurações do ´Debugger Options´ que, aliás, tive o cuidado de manter as mesmas após os testes que realizei, as quais também não tinham sido alteradas desde à instalação inicial. De qualquer modo, agradeço a atenção demonstrada por todos. Creio que só me resta tentar uma reinstalação ou migrar para uma versão superior.


Responder Citar

04/02/2006

Marco Salles

Segui as instruções do colega Marcos Salles, implementado o código que sugeriu no evento OnShow do formulário. O resultado: um travamento que obrigou-me a um reset (risos).


Travar ???? não tem porque .... Na verdade o delphi sobrevive a maioria de exceçoes lançadas e tenta sempre continuar a execuçao do programa

Talvez o colega Marcos tenha razão em afirmar que o modelo proposto não seja válido como exemplo, já que a variável não foi efetivamente utilizada; por outro lado, o CÁLCULO matemático FOI FEITO ou, ao menos tentado, e presume-se que isso seria suficiente para uma manifestação de erro.


[b:e539ea0b3a]Não , porque o compilador não compila estas linhas , Logo ele não ha processára.. é como se não tivesse calculo[/b:e539ea0b3a]

Prova disso, é o colega emerson.en, bem como de outras sugestões propostas em outros tópicos que abordam o mesmo assunto

Não , isto não constitui em uma prova... São situaçoes que são levantadas, mas não constitui ha meu ver em uma regra


Ademais, também já havia tentado exibir o valor da variável ´´x´ para saber se ela fora inicializada (se bem me recordo, isso igualmente ocasionou o travamento da máquina


xiiiiiiiiii

Creio que essas diferenças devem variar de uma versão do Delphi para outra (original ou made in Coreano da Paulista)

Isto eu não posso lhe falar nada a respeito

bem como as configurações do ´Debugger Options´ que, aliás, tive o cuidado de manter as mesmas após os testes que realizei, as quais também não tinham sido alteradas desde à instalação inicial.

Tem todo uma configuração sim

De qualquer modo, agradeço a atenção demonstrada por todos. Creio que só me resta tentar uma reinstalação ou migrar para uma versão superior.


As vezes é algum detalhe bobo , que não aparece na hora.. Tem código que não funciona um dia , outro dia voce tenta e dá.. É que na hora a gente erra e nosso cererbro não detecta.. O chamado ilusão de optica

Mas se voce não tiver muitos componentes de terceiros instalados , definidos ou criados uma reistalação não e bicho de sete cabeças


Responder Citar

04/02/2006

Massuda

Experimentei o código exemplo e o que fez diferença é ter ou não a otimização de código marcada ou não (como citou o Marco).

Gostaria de sugerir que você experimentasse este outro código, pois este independe de configurações do compilador bem como de alguns detalhes sutis relacionados com o processador da sua máquina...
procedure TForm1.FormShow(Sender: TObject);
var
    L: TLabel;
begin
  try
    ShowMessage(´Vai ocorrer um erro...´);
    L.Parent := Self;
    ShowMessage(´Erro não detectado.´);
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;
...o esperado é que apareça ´vai ocorrer um erro...´ seguido da mensagem de access violation. Se aparecer ´erro não detectado´, tem algo muito errado nesta estória.


Responder Citar

05/02/2006

Marco Salles

Outra coisa massuda

O SpiritWWWalker deve ter compilado o projeto e gerado um executável

Ao rodar o programa via executavel , sera que trava a máquina Tb ????


Outra coisa , com ele disse

Creio que já mencionei que tenho pouquíssima experiência em Delphi


Sera que quando ele disse que trava , ele não se refere a nivel de projeto, isto é , ter que para continuar a execução do mesmo , usar o F9
apos a erro gerado.. ( O que para nos é praxi , para ele pode ser travamento )))

É so dicas no intuito de ajudar...


Responder Citar

05/02/2006

Massuda

@Marco

Certamente tem algo estranho nesta estória, pois alguns testaram e já deu para ver que não há travamento. Pode ser algum problema na instalação do Delphi, problema na máquina, etc.


Responder Citar