06-Excecoes-C++BuilderV10

Page 1

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

6. Tratamento de Exceções 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.

EXEMPLO – ALOCAÇÃO DINÂMICA DE MEMÓRIA 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) {

140


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

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.

141


L

U

I

F

S

E

R

N

A

N

D

O

E

S

P

I

N

O

S

A

C

O

C

I

A

N

EXEMPLO – ALOCAÇÃO DIVISÃO POR ZERO 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); } //----------------------------------------------------------------

142


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

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.

143


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

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

144


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

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.

145


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

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

146


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

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.

6.1. Emissão de Exceções 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.

147


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

6.2. Especificação de Exceções 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); // // void SetY(unsigned int _Y) throw (EForaFaixa); // //

Se houver algum problema é criado 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 } }

148


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

} //---------------------------------------------------------------------------

6.3. Captura de Exceções 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:

149


L

U

I

F

S

E

R

N

A

N

D

O

E

S

P

I

N

O

S

A

C

O

C

I

A

N

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.

150


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

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.

6.4. Exceções não Tratadas 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().

151


L

U

I

F

S

E

R

N

A

N

D

O

E

S

P

I

N

O

S

A

C

O

C

I

A

N

6.5. Exceções da VCL 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.

6.5.1. Classes de Exceções 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.

6.5.2. Tratamento de Exceções da VCL 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"); }

152


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

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.

6.5.3. Classes de Exceção Tipicas 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

Captura erros de divisão por zero (para divisão inteira e real,

EZeroDivide

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.

EXEMPLO – DIVISÃO POR ZERO [2] O seguinte programa é uma ampliação do projeto de divisão anteriormente colocado. Neste exemplo se discriminam distintas exceções. //--------------------------------------------------------------------#include <vcl.h>

153


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

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

154


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

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.

155


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

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.

EXERCÍCIO – UM REPRODUTOR DE SONS 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:

156


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

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);

157


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

} } //--------------------------------------------------------------------------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:

158


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.