View
213
Download
0
Embed Size (px)
DESCRIPTION
A correta programação das exceções significa desenhar os algoritmos pensando unicamente na forma habitual em que se deve executar, manipulando as situações extraordinárias à parte. Desta forma se consegue um desenho muito mais estuturado, legível, robusto e fácil de manter. 3. Neste momento o termina a execução do método mais interno e se retorna imediatamente ao método invocador. 140
Citation preview
L U I S F E R N A N D O E S P I N O S A C O C I A N
140
66.. TTrraattaammeennttoo ddee EExxcceeççõõeess As exceções são situações anómalas que requerem de um tratamento
especial e não tem porque ser consideradas como erros. Ao conseguir dominar
toda a programação a qualidade das aplicações que se desenvolvme aumenta
consideravelmente.
O funcionamento geral do mecanismo de emissão e tratamento das
exceções é o seguinte:
1. Existe um método que invoca a execução de outro.
2. O método mais interno se encontra em uma situação que pode ser
considerada como excepcional. Portanto emite uma exceção.
3. Neste momento o termina a execução do método mais interno e se
retorna imediatamente ao método invocador.
4. O método invocador deve capturar a exceção e tratá-la. Parte do
tratamento da exceção pode ser voltar a emití-la ao método que a
invocou.
A correta programação das exceções significa desenhar os algoritmos
pensando unicamente na forma habitual em que se deve executar, manipulando
as situações extraordinárias à parte. Desta forma se consegue um desenho muito
mais estuturado, legível, robusto e fácil de manter.
EEXXEEMMPPLLOO –– AALLOOCCAAÇÇÃÃOO DDIINNÂÂMMIICCAA DDEE MMEEMMÓÓRRIIAA Quando se solicita a alocação de memória do sistema, é habitual que
exista suficiente e que náo haja nenhum problema. Mas se for necessário realizar
uma aplicação robusta deve-se levar em conta a eventualidade de que dita
memória não seja concedida o qual pode complicar enormemente o algoritmo
mais simples.
Veja a seguir uma função escrita na linguagem C que simplesmente tenta
alocar memória de forma dinâmica para três números inteiros:
#include <stdlib.h> #include <stdio.h> //--------------------------------------------------------------------------- void SemExecoes(void); //--------------------------------------------------------------------------- void main(void) {
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
141
SemExecoes(); } //--------------------------------------------------------------------------- void SemExecoes(void){ int *p1, *p2, *p3; p1 = (int*) malloc(sizeof(int)); if (p1 == NULL){ printf("Não há memória suficiente"); abort(); } if (p2 == NULL){ printf("Não há memória suficiente"); abort(); } if (p3 == NULL){ printf("Não há memória suficiente"); abort(); } } //---------------------------------------------------------------------------
Programando em C++ e fazendo uso das exeções:
#include <stdlib.h> #include <stdio.h> //--------------------------------------------------------------------------- void ComExecoes(void); //--------------------------------------------------------------------------- void main(void){ ComExecoes(); } //--------------------------------------------------------------------------- void ComExecoes(void){ int *p1, *p2, *p3; try { p1 = new int; // Comportamento normal. p2 = new int; p3 = new int; } catch(...){ // Comportamento excepcional. printf("Não há memória suficiente"); abort(); } } //---------------------------------------------------------------------------
A norma ANSI C++ especifica que se uma instrução new falhar (porque
não há memória disponível) deve ser emitida uma exceção bad_alloc. As
instruções que podem provocar a emissão de uma exeção ou zona crítica se
englobam dentro de um bloco try{}. Se alguma das instruções do bloco try{}
provocarem uma exeção, o fluxo do programa vai até o final do bloco buscando
um bloco catch(...){} que capture a exeção (se não a encontrar, o programa
termina). Neste caso, a instrução catch(...){} captura qualquer exeção, e em
particular, a exeção bad_alloc. O tratamento se efetua neste caso é a
apresentaçào de uma mensagem de erro e se termina a execução do programa.
L U I S F E R N A N D O E S P I N O S A C O C I A N
142
EEXXEEMMPPLLOO –– AALLOOCCAAÇÇÃÃOO DDIIVVIISSÃÃOO PPOORR ZZEERROO O seguinte programa lê dois valores e calcula o quociente entre ambos. Se
o divisor for zero tenta-se fazer a divisão e o programa emite uma exeção de
divisão por zero (EZeroDivide).
Para executar este exemplo crier um novo projeto com a opção de menu
File + New Application. Usando o Gerenciador de Projetos remova os arquivos da
Unit1 com o botão direito do mouse encima da mesma, selecionar Remove from
project.
Dentro do arquivo Project1.cpp apague tudo o que estiver ali e insira o
seguinte código:
//---------------------------------------------------------------- #include <vcl.h> #pragma hdrstop //---------------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { AnsiString Valor; float Dividendo, Divisor, Quociente; // Lê dados de entrada: dividendo e divisor Valor = InputBox ("Divisão", "Dividendo", ""); // Lê o dividendo e Dividendo = StrToFloat (Valor); // converte-o em float. Valor = InputBox ("Divisão", "Divisor", ""); // Lê o divisor e Divisor = StrToFloat (Valor); // converteo em float. // Calcula quociente. Zona critica: perigo se Divisor for igual a 0 Quociente = Dividendo / Divisor; // Mostrar o resultado ShowMessage ("Quociente = " + AnsiString(Quociente)); return (0); } //----------------------------------------------------------------
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
143
Execute o projeto, e quando aparecer a janela de salvar, salve como
zero.bpr.
Depois de salvo, o projeto é executado abrindo duas janelas de inserção
para os valores de dividendo e divisor e uma janela de apresentação do resultado.
O programa não supõe o tratamento da exceção no caso do usuário inserir
o valor 0 no divisor. Se isto porventura venha a acontecer se produzirá uma
exeção, e por não ser tratada pelo programa, o entorno de programação (IDE do
Builder C++) se encarregará dela.
L U I S F E R N A N D O E S P I N O S A C O C I A N
144
Figura 6-1 - Janela de erro que surge devido a uma exeção EzeroDivide não tratada.
Se for executado diretamente o arquivo executável for a do ambiente de
programação, o sistema operacional irá reagir ao erro da seguinte forma:
Se o usuário pressionar o botão Debug aparece a seguinte janela horrível
(caso ele tenha instalado o Bulder C++, Visual C++ ou algum outro software de
depuração de baixo nível):
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
145
O Windows XP pergunta ao usuário se quiser enviar os dados do erro para
a Microsoft. Se ele quiser ver o que será enviado, ele pode selecionar a opção
click here.
L U I S F E R N A N D O E S P I N O S A C O C I A N
146
Resumindo em poucas palavras, fica horrível para o usuário ter que se
defrontar com este tipo de problema, mais ainda se ele pagou pelo software. Um
errinho imbecil deste tipo (feito pelo próprio usuário) porém não protegido pelo
programador, pode fazer que um programa hiper complexo seja tratado como um
programa “porcaria” pelo usuário (injustamente, é claro).
Para proteger a instrução crítica, capturar e tratar a exeção, instroduzir a
seguinte modificação:
try{ Quociente = Dividendo / Divisor; ShowMessage ("Quociente = " + AnsiString(Quociente)); } catch (...) { ShowMessage ("O divisor não pode ser zero."); Application->Terminate(); }
Para ceder o controle do gerenciamento de exeções a nosso programa deve
se desabilitar a opção pela qual o entorno integrado gerencia as interrupções e
indicar que serão gerenciadas pelo programa. Para isto, selecionar a opção de
menu Tools + Debugger Options e na aba OS Exceptions modificar de acordo com
a Figura 6-2 (retirar a seleção do item Integrated debugging no canto inferior
esquerdo).
Figura 6-2 – Janela Debugger Options
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
147
Assim, é indicado ao depurador do C++Builder que o nosso programa se
encarregará de gerenciar as exeções C++ que possam chegar a ocorrer. Agora ao
executar o programa e introduzindo o valor 0 como divisor aparecerá a janela a
seguir:
Depois disto, o programa sera encerrado.
66..11.. EEmmiissssããoo ddee EExxcceeççõõeess A emissão de uma exceção se realiza usando a função throww(). Quando
se emite uma exceção, em realidade o que se faz é criar um objeto de uma classe
que se indique a throw() que será a própria exceção em si. Costuma ser bastante
útil criar classes de exceções próprias para controlar as situações anómalas de
nossa aplicação. Para ilustrar a emissão de exceções, usaremos o projeto POOEx.
Em ObjGraph.h coloque o seguinte código antes da declaração da classe
TObjGraf:
//--------------------------------------------------------------------------- // Definição da classe EForaFaixa // Classe de exceção por ficar “fora da faixa” de visualização: // sair dos limites do objeto PaintBox ao calcular // as novas coordenadas do desenho da bola. class EForaFaixa{}; //---------------------------------------------------------------------------
Agora podem ser emitidas exceções da seguinte maneira:
throw EForaFaixa();
Mesmo que as exeções sejam classes, em C++ Builder existe a convenção
de que o seu nome comece pela letra E e não por T como o resto das classes.
Mesmo que no exemplo anterior, a classe criada para a exceção não tem nenhum
membro (propriedades e métodos), esses poderão ser adicionados. Eles servirão
para poder incorporar informações no objeto de exceção sobre a situação em que
foi produzida a exceção e poderão ser usados pela seção de código que as trate.
Por exemplo, se houver um método que emite uma exceção por falta de
memória pode ser interessante incorporar uma propriedade que indique qual foi
a máximo tamanho de memória disponível quando foi emitida a exceção.
L U I S F E R N A N D O E S P I N O S A C O C I A N
148
66..22.. EEssppeecciiffiiccaaççããoo ddee EExxcceeççõõeess A linguagem C++ conta com uma característica denominada especificação
de exceções, que serve para enumerar, em uma declaração, as exceções que
pode emitir um determinado método. Se quisermos que um método possa emitir
um determinado tipo de exceção deve se especificar dessa forma. Alterar como
segue em ObjGraf.h, dentro da classe TObjGraf:
//--------------------------------------------------------------------------- // Definição da classe TObjGraf //--------------------------------------------------------------------------- class TObjGraf { private: unsigned int unFX; // foram alterados os nomes unsigned int unFY; // de unX para unFX e unY para unFY void SetX(unsigned int _X) throw (EForaFaixa); // Se houver algum // problema é criado void SetY(unsigned int _Y) throw (EForaFaixa); // um objeto da classe // EForaFaixa virtual int GetLargura (void) = 0; // Método virtual puro virtual int GetAltura (void) = 0; // Método virtual puro
…
Em ObjGraf.cpp:
//--------------------------------------------------------------------------- // Funções de escrita das propriedades virtuais unX e unY void TObjGraf::SetX(unsigned int _X) throw (EForaFaixa) { if (_X < 0){ // Coordenada negativa unFX = 0; // Ajustar para a margem esquerda throw EForaFaixa(); // Emitir uma exeção } else{ if (_X > (PaintBox->Width - unLargo)){ // Alta demais unFX = PaintBox->Width - unLargo;// Ajustar para a margem // direita throw EForaFaixa(); // Emitir uma exeção } else{ unFX = _X; // Correto: escrever sem modificar } } } //--------------------------------------------------------------------------- void TObjGraf::SetY(unsigned int _Y) throw (EForaFaixa) { if (_Y < 0){ // Coordenada negativa unFY = 0; // Ajustar a margem superior throw EForaFaixa(); // Emitir uma exeção } else{ if (_Y > (PaintBox->Height - unAlto)){ // alto demais unFY = PaintBox->Height - unAlto;// Ajustar para a margem //inferior throw EForaFaixa(); // Emitir uma exeção } else{ unFY = _Y; // Correto: escrever sem modificar } }
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
149
} //---------------------------------------------------------------------------
66..33.. CCaappttuurraa ddee EExxcceeççõõeess O bloco suscetível de produzir alguma exceção (zona crítica) se coloca
dentro de um bloco try{}, e a captura (discriminação da exceção que foi
produzida) se efetua em uma instrução catch e o seu processamento se realiza a
continuação no bloco catch.
try{ <bloco de instruções críticas> } catch(<tipo exceção1> <variável>){ <manipulador1> } catch(<tipo exceção2> <variáve2>){ <manipulador2> } ...
Pode se especificar tantos blocos catch para um bloco try quando forem
necessários. No momento que ocorra uma exceção se executará o bloco catch
cuja classe concorde com a da exceção. Se for expecificado catch(...) se
capturará qualquer exceção.
A exceção não tem por que ser emitida explicitamente no bloco try senão
como conseqüência da execução de uma função chamada dentro desse bloco.
Alterar em ObjGraf.cpp:
//--------------------------------------------------------------------------- void TBola::Mover (void) { Apagar (); try{ unX += FDirX * Velocidade; } catch(EForaFaixa){ FDirX = -FDirX; } try{ unY += FDirY * Velocidade; } catch(EForaFaixa){ FDirY = -FDirY; } Mostrar (); } //---------------------------------------------------------------------------
Neste exemplo, a instrução crítica:
unX += FDirX * Velocidade;
traduzida em:
L U I S F E R N A N D O E S P I N O S A C O C I A N
150
unX = unX + FDirX * Velocidade;
e como unX é uma propriedade virtual, na realidade trata-se de fazer:
SetX(unX + FDirX * Velocidade)
Onde se observa que é o método SetX() quem pode provocar a emissão da
exceção.
Em UPrincipal.cpp colocar a seguinte declaração global:
TBola *Bola;
Modificar as funções FormCreate() e FormDestroy() para que fiquem da
seguinte maneira:
//--------------------------------------------------------------------------- void __fastcall TFrmPrincipal::FormCreate(TObject *Sender) { Bola = new TBola (PaintBox, clYellow, 120, 70, 25); } //--------------------------------------------------------------------------- void __fastcall TFrmPrincipal::FormDestroy(TObject *Sender) { delete Bola; } //---------------------------------------------------------------------------
Eliminar o gerenciador para o evento OnPaint do componente PaintBox
(apagando o corpo da função tão somente).
Adicionar ao FrmPrincipal um objeto TTimer (aba System) e fixar a
propriedade Interval = 100.
No evento OnTimer colocar:
//--------------------------------------------------------------------------- void __fastcall TFrmPrincipal::Timer1Timer(TObject *Sender) { Bola->Mover(); } //---------------------------------------------------------------------------
Neste ponto o projeto deve estar como mostra a Figura 6-310.
Figura 6-3 - Dois instantes de movimento da bola.
10 O entorno deve estar configurado para que o programa gerencie as exceções e não o entorno de programação. Se não estiver assim configurado, selecionar Tools + Debugger Options, abrir a aba OS Exceptions e configurar como mostra a Figura 6-2.
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
151
Executando o programa, quando a bola chegar ao limite do componente
TPaintBox haverá a emissão de uma exceção como mostra a figura a seguir.
O entorno deve estar configurado para que o programa gerencie as
exceções e não o entorno de programação. Se não estiver assim configurado,
selecionar Tools + Debugger Options, abrir a aba OS Exceptions e configurar como
mostra a Figura 6-2.
66..44.. EExxcceeççõõeess nnããoo TTrraattaaddaass Se uma exceção que foi emitida não encontrar um manipulador apropriado,
será chamada a função terminate(), que por default realiza um abort().
Entretanto pode se definir uma função própria terminate() com set_terminate().
Uma coisa parecida ocorre se um método emite uma exceção de um tipo
não listado na especificação de exceções, então se chama a função unexpected()
que por default chama a função terminate(). Da mesma maneira que com
terminate() pode se definir a função unexpected() própria com set_unexpected().
L U I S F E R N A N D O E S P I N O S A C O C I A N
152
66..55.. EExxcceeççõõeess ddaa VVCCLL Quando se utilizam componentes da VCL as aplicações é necessário
compreender o mecanismo de tratamento de exceções da VCL. O motivo é que as
exceções estão integradas em numerosas classes e se emitem automaticamente
quando se apresenta uma situação inesperada. Se não se realiza um tratamento
da exceção , a VCL levará a cabo um tratamento default. Normalmente aparece
uma mensagem que descreve o tipo de erro que foi produzido.
66..55..11.. CCllaasssseess ddee EExxcceeççõõeess O C++ Builder incorpora um extenso conjunto de classes de exceção
integradas que permitem tratar automaticamente os erros de divisão por zero, de
entrada/saída de arquivos, conversões de tipos e muitas outras situações
anómalas. Todas as classes de exceção da VCL derivam de um objeto raíz
chamado Exception, que encapsula as propriedades e métodos fundamentais
para todas as exceções por parte das aplicações.
66..55..22.. TTrraattaammeennttoo ddee EExxcceeççõõeess ddaa VVCCLL As exceções de tipo VCL, assim como todas as classes da VCL, devem
estar localizadas no heap (criação dinâmica) e por isso deve se ter em conta o
seguinte:
� As classes de exceção do tipo VCL somente podem ser capturadas por ponteiro ou
por referência (preferencialmente).
� As exceções do tipo VCL devem ser emitidas com sintaxe “por valor”.
As exceções podem ser passadas a um bloco catch que toma um
parämetro do tipo Exception. Utilizar a seguinte sintaxe para capturar as
exceções da VCL:
catch(const exception_class & exception_variable)
Se especifica a classe de exceção que se deseja capturar e se proporciona
uma variável por meio da qual se faz referência à exceção. Por exemplo:
//-------------------------------------------------------- #include <vcl.h> #pragma hdrstop //-------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { try { throw Exception("Minha exceção VCL"); }
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
153
catch (const Exception & E) { ShowMessage("Classe da exceção capturada: " + AnsiString(E.ClassName()) + "\nMessage: " + E.Message); } return (0); } //--------------------------------------------------------
A sentença throw do exemplo anterior cria uma instância da classe
Exception e chama o seu construtor. Todas as exceções que descendem de
Exception contam com uma mensagemque se pode apresentar na tela, passar aos
construtores e serem recuperadas mediante a propriedade Message. O resultado
do programa anterior é o mostrado na Figura 6-4.
Figura 6-4 - Ejemplo de lanzamiento y captura de excepción VCL.
66..55..33.. CCllaasssseess ddee EExxcceeççããoo TTiippiiccaass Mesmo que as exeções não necessariamente indiquem um erro na
execução de uma aplicação, as exceções da VCL costumam ser erros sim. Veja a
seguir uma lista das classes de exceção mais utilizadas em C++ Builder.
Classe Descrição
EAccessViolation Erro de acceso à memoria.
EDatabaseError Especifica um erro de aceso à base de dados.
EDBEditError Dados incompatíveis com uma máscara especificada.
EDivByZero
EZeroDivide
Captura erros de divisão por zero (para divisão inteira e real,
respectivamente).
EInOutError Representa um erro de E/S de arquivo.
EInvalidPointer Operações não válidas com ponteiros.
EPrinterError Indica um erro de impressão.
Mesmo que todas essas classes funcionem da mesma maneira, cada uma
delas possui particularidades derivadas da exceção concreta que elas indicam.
EEXXEEMMPPLLOO –– DDIIVVIISSÃÃOO PPOORR ZZEERROO [[22]] O seguinte programa é uma ampliação do projeto de divisão anteriormente
colocado. Neste exemplo se discriminam distintas exceções.
//--------------------------------------------------------------------- #include <vcl.h>
L U I S F E R N A N D O E S P I N O S A C O C I A N
154
#pragma hdrstop //--------------------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { AnsiString Valor; float Dividendo, Divisor, Quociente; float sigo = true; while (sigo) { try { // Ler e converter dividendo Valor = InputBox ("Divisão", "Dividendo", ""); Dividendo = StrToFloat (Valor); if (Dividendo == 0) { sigo = false; } else { // Ler e converter divisor Valor =InputBox ("Divisão", "Divisor", ""); Divisor = StrToFloat (Valor); Quociente = (Dividendo / Divisor); ShowMessage ("Quociente = " + AnsiString(Quociente)); } } // try // Se captura se foi realizada uma divisão por zero. catch (EZeroDivide & ) { ShowMessage ("O divisor não pode ser zero."); } // Mais geral: se alcanza se não se captura a anterior. catch (Exception & e) { ShowMessage ("Se produziu uma exceção: " + AnsiString(e.ClassName())+ "\n " + e.Message); } } // while sigo return (0); } //---------------------------------------------------------------------
Se for tentado realizar uma divisão por zero, o resultado é o indicado na
Erro! Fonte de referência não encontrada..
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
155
Agora, se for introduzido um dado incorreto, a função StrToFloat() emite
uma exceção EConvertError que se captura no último bloco catch. Ver a Figura
6-5.
Figura 6-5 - Exemplo de entrada incorreta.
Mais ainda, se for produzido algum tipo de overflow também pode ser
controlado com o último bloco catch, como mostra a Figura 6-6.
(a)
(b)
Figura 6-6 - Exemplos de overflow: a) na entrada de dados e b) no cálculo do quociente.
L U I S F E R N A N D O E S P I N O S A C O C I A N
156
Para finalizar, adicionar o seguinte bloco catch entre os dois anteriores e
considerar (uma parte da) a hierarquia das classes de exceções:
TObject-->Exception-->EExternal-->EMathError-->(EZeroDivide, EOverflow, ...)
catch (EMathError & e) { ShowMessage ("Operação inválida: " + e.Message); }
(a)
(b)
Figura 6-7 - Outra maneira de capturar overflows: a) na entrada de dados e b) no cálculo do quociente.
EEXXEERRCCÍÍCCIIOO –– UUMM RREEPPRROODDUUTTOORR DDEE SSOONNSS Neste exemplo se criará uma quadro que conterá um
componente MediaPlayer que servirá para reproduzir arquivos .WAV.
Será utilizado o gerenciamento de exceções para controlar a correta
execução do programa.
O primeiro passo é criar e configurar o projeto. Para isto usar a opção File
+ New Application. Salvar em nova pasta com a opção de menu File + Save
Project As... Salvar como UPrincipal.cpp (Unit1.cpp) e Som.bpr (Project1.bpr).
A seguir, configurar o quadro para aparecer como mostra a seguinte
figura:
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I
157
Alterar o título do quadro (Caption) para Sons e adicionar os seguintes
componentes:
� Quatro botões normais (TButton) chamados (Name): LogoffBtn, MSSoundBtn, ErrorBtn e OutrosBtn com o texto (Caption) como indicado na figura anterior.
� Um botão BitBtn para terminar o programa.
� Um controle MediaPlayer (aba System) não-visível (Visble = false).
� Um quadro de diálogo OpenDialog (aba Dialogs).
A seguir, escreveremos os gerenciadores de eventos associados à pulsação
dos botões. O gerenciamento das interrupções capturadas (exceções) será
realizada com uma função comum cujo protótipo é:
void Erro(AnsiString & name, Exception & e);
Esta função é declarada acima de todas as funções em UPrincipal.cpp. Os
gerenciadores dos eventos OnClick associados aos botões serão os seguintes:
//--------------------------------------------------------------------------- void __fastcall TForm1::LogoffBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\Windows XP Logoff Sound.wav"; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e); } } //--------------------------------------------------------------------------- void __fastcall TForm1::MSSoundBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\Windows XP Startup.wav"; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e);
L U I S F E R N A N D O E S P I N O S A C O C I A N
158
} } //--------------------------------------------------------------------------- void __fastcall TForm1::ErrorBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\NaoHa.wav"; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e); } } //--------------------------------------------------------------------------- void __fastcall TForm1::OutrosBtnClick(TObject *Sender) { if (OpenDialog->Execute()){ MediaPlayer1->FileName = OpenDialog->FileName; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e); } } // if (OpenDialog1->Execute()) } //--------------------------------------------------------------------------- void Erro(AnsiString & name, Exception & e){ ShowMessage ("Falha na reprodução do arquivo de som: " + name + "\nExceção: " + AnsiString(e.ClassName()) + "\nDetalhes: " + AnsiString(e.Message)); } //--------------------------------------------------------------
Quando o programa é executado e for apertado o botão Erro (supõe-se que
o arquivo não existe) aparecerá a seguinte janela de mensagem: