핸들링 하지 못한 에러 잡기
신이 아니고서야 프로그램에서 에러발생하지 않는경우는 없을것입니다.
try-catch (delphi : try - except ) 로 에러를 잡아서 처리합니다만
생각지도 못한 곳에서 에러가 발생하는경우가 있을것입니다.
이런 경우어떻게 처리하십니까?
TApplication의 OnException이벤트 핸들러
Application객체에 보면 OnException이라는 이벤트 핸들러가 있습니다.
함수형태는 TExceptionEvent 형으로써
델파이의 경우
TExceptionEvent = procedure ( Sender: TObject; E: Exception) of object ;
C++Builder로 표현하면
typedef void __fastcall ( __closure * TExceptionEvent)
( System: : TObject* Sender, Sysutils: : Exception* E) ;
OnException이벤트 핸들러 호출하는 곳
이 Application.OnExcptiption은 Application.HandleException에서 호출해줍니다.
procedure TApplication. HandleException( Sender: TObject) ;
begin
if GetCapture <> 0 then SendMessage( GetCapture, WM_CANCELMODE, 0, 0) ;
if ExceptObject is Exception then
begin
if not ( ExceptObject is EAbort) then
if Assigned( FOnException) then //이벤트 핸들러가 설정되어있는경우 호출해줌
FOnException ( Sender, Exception( ExceptObject) )
else
ShowException ( Exception( ExceptObject) ) ;
end
SysUtils . ShowException( ExceptObject, ExceptAddr) ;
end ;
Application.HandleException을 호출하는곳
그럼 Application.HandleException은 어디서 호출해주냐면?
1) TCustomForm에서 예외 발생시 Application.HandleException을 호출합니다.
2) TWinControl의 MainWndProc에서 WindowProc를 호출해주고 예외가 발생하면
Application.HandleException을 호출합니다.
3) TDragObject의 WndProc와 MainWndProc에서 예외발생시 Application.HandleException을 호출합니다.
4) TDataModule의 HandleCreateException 와 DoDestroy 에서 예죄발생시 호출합니다.
5) 기타 StdCtrls , ComCtrls , ExtCtrls 등의 각종 Control및 Component에서도 예외발생시 호출해주는 곳이 많습니다.
Timer 또는 ADOConnection등의 Component에서도 호출합니다.
* 특이사항
; GraphicControl의 WndProc에서는 Application.HandleException 을 직접 호출하지는 않습니다.
만약 GraphicControl의 WndProc에서 예외가 발생하면 해당 GraphicControl이 소속된 WinControl의 WindowProc에서
except가 잡혀서 거기서 Application.HandleException가 호출됩니다.
=> 이경우 GraphicControl의 이벤트 핸들러(MouseDown/Move/Up등)에서 예외가 발생하더라도
Application.OnException으로 넘어오는 Sender가 GraphicControl이 아니라
Parent인 WinControl이 Sender가 될것입니다.
* TPopupMenu , TMenuItem에서 예외발생시 PopupList가 Application.HandleException을 호출한다.
* Action은 Application.OnIdle에서 호출하므로 예외발생 객체도 모두 Application이 된다.
TApplication의 OnException 사용예
; 이제 이 이벤트 핸들러를 사용한 예제를 살펴 보겠습니다.
void __fastcall TForm1: : FormCreate( TObject * Sender)
{
//TApplication은 TComponent를 상속받은 놈인데 Name이 정해지지 않은상태다
//(별로 쓸일이 없으니)
// Application에서 HandleException을 호출한경우
// Sender가 Application이되는데.. 이를 위해 이름을 정해줌
Application->OnException = "TApplication";
//프로그램 시작시 Application->OnException 이벤트 핸들러를 걸어준다.
Application->OnException = AppException;
}
//---------------------------------------------------------------------------
void __fastcall TForm1: : AppException( System: : TObject* Sender, Sysutils: : Exception* E)
{
String sObj = "" ;
if ( Sender)
{
if ( Sender->InheritsFrom( __classid( TControl) ) )
{
TControl * ctrl= ( TControl * ) Sender;
while ( ctrl)
{
sObj = ctrl->Name+ " -> " + sObj;
ctrl = ctrl->Parent;
}
}
else if ( Sender->InheritsFrom( __classid( TComponent) ) )
{
TComponent * Comp= ( TComponent * ) Sender;
sObj = Comp->Name;
if ( Comp->Owner)
{
sObj = Comp->Owner->Name + " -> " + sObj;
}
}
}
String sExpMsg = sObj + " Msg:" + E->Message;
//Log를 저장하거나.. SaveLog ..
//필요에 따라 메세지를 뿌려준다.
E->Message = sExpMsg;
Application->ShowException ( E) ;
}
메인 쓰레드에서 GUI Component및 Control에서 발생하는 예외는
모두 Application.OnException에서 잡아서 확인할수 있습니다
코드에서 잡지 못한 예외는 Application.OnException으로 처리하기를 권합니다.
참 위 코드에서 TControl인 경우와 TComponent인경우 분리되어있는데..
Timer같은경우 Component이지만 Control은 아니므로 Parent가 없기때문에 분리되어있습니다.
TComponent를 상속받지 않은 Object는 Name을 알수 없으므로.. 따로 처리하지 않았구요
그럼..