SEH (Structured Exception Handling) 예외처리
__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)
: 함수 본체가 정의되어 있지 않으며 컴파일시 코드가 직접 삽입되어 예외처리를 보조하는 매크로 함수
GetExceptionCode()
: 예외 종류 조사 함수. MSDN GetExceptionCode Macro
__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에서 예외발생시 
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 등도 해당된다.  


사용자 정의 exception 던지기
RaseException() 호출하여 예외를 던질 수 있다. 

처리되지 않은(unhandled exception) 처리
처리되지 않은 예외 발생시 OS로 넘어가게 되면 프로그램이 종료되므로
이에 대비하기 위해 프로그램 초기화 부분에 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