Array
(
)

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

Spiritwwwalker
   - 03 fev 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.


Emerson
   - 03 fev 2006

coloque isso num botão para testar:

#Código

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.


Massuda
   - 03 fev 2006

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...#Código

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 Stop on Delphi Exceptions que está em Tools|Debugger options|Language exceptions (talvez o menu possa ser diferente dependendo da versão de Delphi que você usa)


Truck1n
   - 03 fev 2006

Try ... Except ... end;

é tratamento de erros.

Try ... Finally ... end;

Proteção de recursos

#Código


a: Integer;

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

********

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




Spiritwwwalker
   - 04 fev 2006

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.


Emerson
   - 04 fev 2006

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.


Marco Salles
   - 04 fev 2006

Deixe eu participar um pouquinho desta calorosa discusão

O código que voce postou não vale para Exemplo

#Código

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;


Não vale porque o compilador ignora simplesmente as instruçoes
y := 0;
x := 3 div y;

Ele ignora estas linhas devido ao falto de não usa-las ...Este é um recurso do compilador e ja foi outrora discudido aqui no Forum

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


Percebo ainda que falta a estrutura citada pelo massuda


Citação:
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 é EDivByZero

Corrigindo seria isto :

#Código
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;


Mas ainda tem o Finally , 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 :

#Código
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...


Emerson
   - 04 fev 2006


Citação:
Deixe eu participar um pouquinho desta calorosa discusão

O código que voce postou não vale para Exemplo
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:
#Código

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.


Marco Salles
   - 04 fev 2006


Citação:
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

Mas o exemplo que voce deu :


Citação:
try
strtoint(´a´);
except
showmessage(´erro ao converter valor´)
end;



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


O Erro ira aparecer , :arrow: porque o compilador compila estas isntruçoes.. Aqui tb deu erro neste caso e no primeiro caso não deu... Verifique por gentileza se o seu compilador esta compilando as instruçoes
y := 0;
x := 3 div y;
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
ShowMessage(´Erro de divisão por zero.´); e não esta
ShowMessage(´Vai ocorrer um erro.´);


Emerson
   - 04 fev 2006

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 Stop on Delphi exceptions, pois eu sempre trato minhas exceções e não preciso dela marcada.


Marco Salles
   - 04 fev 2006


Citação:
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 :?: :?: :?:

Mas uma vez eu pergunto..

Verifique por gentileza se o seu compilador esta compilando as instruçoes
y := 0;
x := 3 div y;

:!: :!: :!:
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

#Código

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 :?: :?: :?: :?: :?:


Spiritwwwalker
   - 04 fev 2006

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.


Marco Salles
   - 04 fev 2006


Citação:
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


Citação:
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.


Não , porque o compilador não compila estas linhas , Logo ele não ha processára.. é como se não tivesse calculo


Citação:
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



Citação:
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


Citação:
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


Citação:
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


Citação:
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


Massuda
   - 04 fev 2006

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...#Código

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.


Marco Salles
   - 05 fev 2006

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


Citação:
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...


Massuda
   - 05 fev 2006

@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.


Spiritwwwalker
   - 06 fev 2006

Prezados colegas:

Após exaustivos testes, inúmeras consultas aos meus compêndios, saudades do VBA, visão turva que me fazia enxergar a palavra ´Java´ diante de meus olhos, centenas de fios de cabelos perdidos, etc., cheguei à seguinte conclusão:

A minha versão do Delphi estava macumbada. :shock:

Percebam o emprego do verbo no passado (´estava´), isso porque desinstalei a versão 6 e instalei a boa e velha 5. Desabilitei a opção ´Stop On Delphi Exceptions´ em ´Debugger Options´ e, agora, finalmente consegui obter mensagens personalizadas quando da ocorrência de erros/exceções. Esclareço ao colega Marco Salles que, ao menos nesta versão (5), o código não acusou nenhum erro ENQUANTO não utilizei a variável que recebeu o resultado de uma divisão por zero. Por outro lado, não foi necessário tratar de maneira específica uma exceção dessa natureza (EdivByZero), bastando um procedimento genérico como se segue, o qual foi ´chamado´ a partir do evento OnShow de um Form qualquer:


procedure GerarErro();
var
x, y : integer;
strValor : string;
begin
try
y := 0;
x := 3 div y;
strValor := IntToStr(x);
ShowMessage(´O valor de x é: ´ + strValor);
except
on e: exception do
showMessage(´Ocorreu o seguinte erro: ´ + e.message);
end;
end;


E, aparentemente, os travamentos também cessaram.
Gostaria de agradecer, mais uma vez, a atenção e a boa vontade demonstrada pelos colegas, bem como consignar a solução (um tanto radical, é verdade...) de um problema que estava se tornando um pesadelo. Fica a seguinte lição:

´Programa de computador vendido por coreano é que nem CD de jogo comprado na banca: não funciona nunca´.

Se alguém aqui tiver um cunhado caminhoneiro e ele não souber o que escrever no pára-choque... (risos).


Marco Salles
   - 08 fev 2006

So para não ficar uma má impressão , porque estes estes tópicos e experiencias trocadas servem como futura consulta sobre o assunto , quero deixar claro dois pontos


Citação:
Esclareço ao colega Marco Salles que, ao menos nesta versão (5), o código não acusou nenhum erro ENQUANTO não utilizei a variável que recebeu o resultado de uma divisão por zero.


Esta situação é a correta


Citação:
Por outro lado, não foi necessário tratar de maneira específica uma exceção dessa natureza (EdivByZero), bastando um procedimento genérico como se segue, o qual foi ´chamado´ a partir do evento OnShow de um Form qualquer:


Esta vendo um mau entendido.. Quando eu mencionei usar a exceção
EdivByZero , foi porque aparentemente a exceção gerada seria dessa natureza... Com certeza , o uso de uma exceção mais generica pega tb esse tipo de erro.. O que quis com isso foi endossar a estrutura passada pelo massuda .
De forma nenhuma afirmei que não estava pegando porque simplesmente voce estva tratando de forma errada a exceção lançada
Uma exceção generica ´pega´ equalquer tipo de erros e por isso voce deve deixa-la por ultimo na estrutura.. Ja uma exceção OnByDivZero não pega outras exceçoes lançadas pelo sistema etc...


Citação de massuda

Citação:
No caso do try..except, você pode definir vários on...do, cada um para um tipo diferente de exceção. Por exemplo...Código:
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;