SEH (Structured Exception Handling) 예외처리
__try, __finally의 괜찮은 사용 예제
__finally 에서만 사용할 수 있는 AbnormalTermination() 함수
사용자 정의 exception 던지기
처리되지 않은(unhandled exception) 처리
__try ~ __except, __try ~ _finally 형태로 쓰임.
(실제 visual c++에선 try~catch~finally는 SEH로 구현됨)
__except()문에 쓰이는 필터식
EXCEPTION_EXECUTE_HANDLER(1) : 예외 발생시 __except 블럭의 코드가 실행
EXCEPTION_CONTINUE_EXECUTION(-1): 예외 발생시 __except 블럭의 코드를 실행하지 않고 예외 발생 지점에서 재실행
EXCEPTION_CONTINUE_SEARCH(0) : 상위 __except()문을 실행. 하위 __except()문의 코드는 실행되지 않는다.
내재함수(Intrinsic Function)
: 함수 본체가 정의되어 있지 않으며 컴파일시 코드가 직접 삽입되어 예외처리를 보조하는 매크로 함수
__except 괄호 안이나 __except 블럭 안에서만 사용 가능.
GetExceptionInformation()
: 예외 상세 정보 및 예외 발생시 기계 상태 정보 조사 함수
__except 괄호 안에서만 리턴받은 정보 구조체가 유효하기 때문에
__except 블럭 안에서 해당 정보를 참조하려면 따로 변수에 담아줘야 한다.
GetExceptionInformation()
: 예외 상세 정보 및 예외 발생시 기계 상태 정보 조사 함수
__except 괄호 안에서만 리턴받은 정보 구조체가 유효하기 때문에
__except 블럭 안에서 해당 정보를 참조하려면 따로 변수에 담아줘야 한다.
__leave
: __leave를 만나면 바로 __finally로 이동한다.
__try { _tprintf(_T(" 1\n")); __leave; //goto __finally 같은 의미 _tprintf(_T(" 2\n")); } __finally { _tprintf(_T(" 3\n")); }
__except() 필터식 및 __leave 샘플
#include#include #include int ddd; // 어떤 필터식을 사용할지 동적으로 정의하기 위한 함수 DWORD ExceptionFilter(DWORD exceptionType) { switch (exceptionType) { case EXCEPTION_INT_DIVIDE_BY_ZERO: _tprintf(_T(" change ddd to 1\n")); ddd = 1; return EXCEPTION_CONTINUE_EXECUTION; break; default: return EXCEPTION_CONTINUE_EXECUTION; //원래는 EXCEPTION_EXECUTE_HANDLER } } int main(void) { _tprintf(_T("\nEXCEPTION_EXECUTE_HANDLER\n")); //예외 발생시 __except 블럭의 코드가 실행된다. TCHAR* str = NULL; __try { _tcscpy(str, _T("Test")); } __except(EXCEPTION_EXECUTE_HANDLER) { _tprintf(_T(" Exception\n")); } _tprintf(_T("\nEXCEPTION_CONTINUE_EXECUTION\n")); //예외 발생시 __except 블럭의 코드를 실행하지 않고 예외 발생 지점에서 재실행 __try { ddd = 0; _tprintf(_T(" ddd = %d\n"), ddd); int i = 2/ddd; _tprintf(_T(" ddd = %d\n"), ddd); } __except(ExceptionFilter(GetExceptionCode())) { _tprintf(_T(" 실행안됨\n")); //__except(ddd=1, EXCEPTION_CONTINUE_EXECUTION) //먹통 //__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ? ddd=1, EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER) //먹통 } _tprintf(_T("\nEXCEPTION_CONTINUE_SEARCH\n")); //중첩된 __try 문에서 상위 __except()문을 실행 __try { __try { ddd=0; int i= 2/ddd; } __except(EXCEPTION_CONTINUE_SEARCH) { _tprintf(_T(" 실행안됨\n")); } } __except(EXCEPTION_EXECUTE_HANDLER) { _tprintf(_T(" Exception\n")); } _tprintf(_T("\n__leave\n")); //__leave를 만나면 바로 __finally로 이동한다. __try { _tprintf(_T(" 1\n")); _tprintf(_T(" 2\n")); __leave; _tprintf(_T(" 3\n")); } __finally { _tprintf(_T(" __finally\n")); } return 0; }
__finally 가 실행되지 않는 경우
__try, __finally 블록 사용시 항상 __finally가 호출될 보장을 받을 수 없다.
Windows XP의 경우 스택이 가득차버린 상태에서 __try에서 예외발생시
Windows XP의 경우 스택이 가득차버린 상태에서 __try에서 예외발생시
WER 코드(Windows Error Reporting : 윈도우 에러 보고)도 예외 발생한 프로세스에서 수행되기 때문에
에러 보고를 위한 스택 공간이 없어서 __finally가 실행되지 않고 프로세스는 조용히 죽어 버린다.
SEH 체인 손상이나 예외 필터에서 또 다른 예외 발생시에도 __finally가 실행되지 않는다.
Windows Vista 이후로는 에러 보고 기능을 독립된 프로세스를 이용하도록 변경되었다.
__try 블럭에서 ExitThread, ExitProcess, TerminateThread, TerminateProcess, 내부적으로 ExitProcess를 호출하는 abort()같은 함수 사용시 __finally 블록은 실행되지 않는다.
__try, __finally의 괜찮은 사용 예제
BOOL ret = FALSE; HANDLE hFile = INVALID_HANDLE_VALUE; __try { hFile = CreateFile(_T("test.dat"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTRING, 0, NULL); if( hFile = INVALID_HANDLE_VALUE ) { __leave; } // .. 다른 처리들 .. } __finally { if( hFile != INVALID_HANDLE_VALUE ) CloseHandle(hFile); } return (ret);
__finally 에서만 사용할 수 있는 AbnormalTermination() 함수
AbnormalTermination() 함수는 __finally 블록 안에서만 사용할 수 있으며
__try 에서 예외 발생으로 인해 __finally 블록이 실행되었다면 TRUE를 리턴하고
예외없이 __finally 블록이 실행된다면 FALSE를 리턴한다.
TRUE를 리턴하는 경우는 __try 블록에서 예외 발생 이외에 goto, return, break, continue 등도 해당된다.
__try 에서 예외 발생으로 인해 __finally 블록이 실행되었다면 TRUE를 리턴하고
예외없이 __finally 블록이 실행된다면 FALSE를 리턴한다.
TRUE를 리턴하는 경우는 __try 블록에서 예외 발생 이외에 goto, return, break, continue 등도 해당된다.
사용자 정의 exception 던지기
RaseException() 호출하여 예외를 던질 수 있다.
처리되지 않은(unhandled exception) 처리
처리되지 않은 예외 발생시 OS로 넘어가게 되면 프로그램이 종료되므로
이에 대비하기 위해 프로그램 초기화 부분에 SetUnhandledExceptionFilter()로 필터함수를 등록하면
처리되지 않은 예외 발생시 실행될 메소드를 지정할 수 있다.
SetUnhandledExceptionFilter로 프로세스에 속한 모든 스레드의 처리되지 않은 예외를 처리할 수 있다.
이에 대비하기 위해 프로그램 초기화 부분에 SetUnhandledExceptionFilter()로 필터함수를 등록하면
처리되지 않은 예외 발생시 실행될 메소드를 지정할 수 있다.
SetUnhandledExceptionFilter로 프로세스에 속한 모든 스레드의 처리되지 않은 예외를 처리할 수 있다.
'C++' 카테고리의 다른 글
OLEDB (0) | 2011.01.24 |
---|---|
COM (0) | 2011.01.24 |
MFC 기초 정리 (0) | 2011.01.21 |
파일 비동기 IO 조작 (Async IO) (0) | 2011.01.18 |
윈도우 GUI에서 콘솔(console) 띄우기 (0) | 2011.01.11 |
Windows 접근 제어 (0) | 2011.01.11 |
CRITICAL_SECTION을 사용한 Lock 클래스 예제 (0) | 2011.01.07 |
Design Patterns (디자인 패턴) (0) | 2011.01.06 |