//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
// SEHException.cpp : Definiuje punkt wejścia dla aplikacji konsoli
//

#include "stdafx.h"
#include <string>
#include <iostream>
#include <stdexcept>

int EvalException ( int exception, LPEXCEPTION_POINTERS pinfo)
{
	// Przekazanie większości wyjątków
	switch(exception)
	{
	case EXCEPTION_ACCESS_VIOLATION:
		std::cout << "EXCEPTION_ACCESS_VIOLATION 0x" << std::hex << exception << std::endl;
		break;
	case EXCEPTION_BREAKPOINT:
		std::cout << "EXCEPTION_BREAKPOINT 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_DATATYPE_MISALIGNMENT:
		std::cout << "EXCEPTION_DATATYPE_MISALIGNMENT 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_SINGLE_STEP:
		std::cout << "EXCEPTION_SINGLE_STEP 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
		std::cout << "EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_FLT_DENORMAL_OPERAND:
		std::cout << "EXCEPTION_FLT_DENORMAL_OPERAND 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
		std::cout << "EXCEPTION_FLT_DIVIDE_BY_ZERO 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_FLT_INEXACT_RESULT:
		std::cout << "EXCEPTION_FLT_INEXACT_RESULT 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_FLT_INVALID_OPERATION:
		std::cout << "EXCEPTION_FLT_INVALID_OPERATION 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_FLT_OVERFLOW:
		std::cout << "EXCEPTION_FLT_OVERFLOW 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_FLT_STACK_CHECK:
		std::cout << "EXCEPTION_FLT_STACK_CHECK 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_FLT_UNDERFLOW:
		std::cout << "EXCEPTION_FLT_UNDERFLOW 0x" << std::hex << exception << std::endl;
		break;
	case EXCEPTION_INT_DIVIDE_BY_ZERO:
		std::cout << "EXCEPTION_INT_DIVIDE_BY_ZERO 0x" << std::hex << exception << std::endl;
		break;
	case EXCEPTION_PRIV_INSTRUCTION:
		std::cout << "EXCEPTION_PRIV_INSTRUCTION 0x" << std::hex  << exception << std::endl;
		break;
	case EXCEPTION_NONCONTINUABLE_EXCEPTION:
		std::cout << "EXCEPTION_NONCONTINUABLE_EXCEPTION 0x" << std::hex  << exception << std::endl;
		break;
	}

	std::cout << "Kod: 0x" << std::hex << pinfo->ExceptionRecord->ExceptionCode << std::endl;
	std::cout << "Znaczniki: " << ((pinfo->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) ? "Możliwość kontynuachu" : "Bez możliwości kontynuacji")  << std::endl;
	std::cout << "Rekord wyjątku: 0x" << std::hex << pinfo->ExceptionRecord->ExceptionRecord  << std::endl;
	std::cout << "Adres: 0x" << std::hex << pinfo->ExceptionRecord->ExceptionAddress << std::endl;
	std::cout << "Liczba parametrów: " << pinfo->ExceptionRecord->NumberParameters << std::endl;
	if(exception == EXCEPTION_ACCESS_VIOLATION)
	{
		if(pinfo->ExceptionRecord->ExceptionInformation[0] == 0)
			std::cout << "Próba odczytu niedostępnych danych 0x" << std::hex << pinfo->ExceptionRecord->ExceptionInformation[1] << std::endl;
		else if(pinfo->ExceptionRecord->ExceptionInformation[0] == 1)
			std::cout << "Próba zapisu niedostępnych danych 0x" << std::hex << pinfo->ExceptionRecord->ExceptionInformation[1] << std::endl;
	}

	// EXCEPTION_EXECUTE_HANDLER       1
	// EXCEPTION_CONTINUE_SEARCH       0
	// EXCEPTION_CONTINUE_EXECUTION    -1
    return EXCEPTION_EXECUTE_HANDLER;
}
class SpecialClass
{
public:
	void Output()
	{
		std::cout << "Wywołanie SpecialClass::Output()" << std::endl;
	}
};

void SEHExceptions()
{
	__try
	{
		int a = 0;
		int b = 1;
		int c = b/a;
		std::cout << "Wynik to: " << c << std::endl;
	}
	__except( EvalException(GetExceptionCode(), GetExceptionInformation()) )
	{
		std::cout << "Przechwycono wyjątek" << std::endl;
	}

	__try
	{
		int *p = 0;
		std::cout << "Wartość to: " << p[1] << std::endl;
	}
	__except( EvalException(GetExceptionCode(), GetExceptionInformation()) )
	{
		std::cout << "Przechwycono wyjątek " << std::endl;
	}

	__try
	{
		SpecialClass *p = 0;
		p->Output();
	}
	__except( EvalException(GetExceptionCode(), GetExceptionInformation()) )
	{
		std::cout << "Przechwycono wyjątek " << std::endl;
	}
}

class custom_exception : public std::exception
{
public:
	explicit custom_exception(const std::string& _message) : message(_message)
	{
	}

	virtual ~custom_exception()
	{
	}

	virtual const char *what()
	{
		return (message.c_str());
	}

private:
	// Wiadomość
	std::string message;
};


void EHExceptions()
{
	try
	{
		int a = 0;
		int b = 1;
		int c = b/a;
		std::cout << "Wynik to: " << c << std::endl;
	}
	catch(std::exception)
	{
		std::cout << "Przechwycono wyjątek EH " << std::endl;
	}
	catch(...)
	{
		std::cout << "Domyślnie przechwycono wyjątek EH " << std::endl;
	}

	try
	{
		int *p = 0;
		std::cout << "Wartość to: " << p[1] << std::endl;
	}
	catch(std::exception)
	{
		std::cout << "Przechwycono wyjątek EH " << std::endl;
	}
	catch(...)
	{
		std::cout << "Domyślnie przechwycono wyjątek EH " << std::endl;
	}
	try
	{
		throw custom_exception("To jest test");
	}
	catch(custom_exception& e)
	{
		std::cout << "Przechwycono własny wyjątek: " <<  e.what() << std::endl;
	}
}


int _tmain(int argc, _TCHAR* argv[])
{
	SEHExceptions();
	EHExceptions();
	return 0;
}

