
#include "stdafx.h"

/////////////////////////////////////////////////////////////////////////////
// CException

static  LPCTSTR pszRTMsg[] =
{
_T("The thread tried to read from or write to a virtual address for which it does not have the appropriate access.\n"),
_T("The thread tried to access an array element that is out of bounds.\n"),
_T("A breakpoint was encountered.\n"),
_T("The thread tried to read or write data that is misaligned.\n"),
_T("One of the operands in a floating-point operation is denormal.\n"),
_T("The thread tried to divide a floating-point value by a floating-point divisor of zero.\n"),
_T("The result of a floating-point operation cannot be represented exactly as a decimal fraction.\n"),
_T("This exception represents any floating-point exception not included in this list.\n"),
_T("The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.\n"),
_T("The stack overflowed or underflowed as the result of a floating-point operation.\n"),
_T("The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.\n"),
_T("The thread tried to execute an invalid instruction.\n"),
_T("The thread tried to access a page that was not present, and the system was unable to load the page.\n"),
_T("The thread tried to divide an integer value by an integer divisor of zero.\n"),
_T("The result of an integer operation caused a carry out of the most significant bit of the result.\n"),
_T("An exception handler returned an invalid disposition to the exception dispatcher.\n"),
_T("The thread tried to continue execution after a noncontinuable exception occurred.\n"),
_T("The thread tried to execute an instruction whose operation is not allowed in the current machine mode.\n"),
_T("A trace trap or other single-instruction mechanism signaled that one instruction has been executed.\n"),
_T("The thread used up its stack.\n")
};

void CException::GetErrorMessage(LPTSTR pszError, DWORD nSize)
{
    DWORD cb = ::FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM 
                              //| FORMAT_MESSAGE_ALLOCATE_BUFFER
                              , NULL, m_hResult
                              , 0 // search from Language neutral to US English 
                              , (LPTSTR)&pszError, nSize, NULL);

    if (0 == cb)    // No message found
    {
        // Try to decode run-time exception
        int n = -1;

        switch (m_hResult)
        {
        case EXCEPTION_ACCESS_VIOLATION:
            n = 0;  break;

        case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
            n = 1;  break;

        case EXCEPTION_BREAKPOINT:
            n = 2;  break;

        case EXCEPTION_DATATYPE_MISALIGNMENT:
            n = 3;  break;

        case EXCEPTION_FLT_DENORMAL_OPERAND:
            n = 4;  break;

        case EXCEPTION_FLT_DIVIDE_BY_ZERO:
            n = 5;  break;

        case EXCEPTION_FLT_INEXACT_RESULT:
            n = 6;  break;

        case EXCEPTION_FLT_INVALID_OPERATION:
            n = 7;  break;

        case EXCEPTION_FLT_OVERFLOW:
            n = 8;  break;

        case EXCEPTION_FLT_STACK_CHECK:
            n = 9;  break;

        case EXCEPTION_FLT_UNDERFLOW:
            n = 10; break;

        case EXCEPTION_ILLEGAL_INSTRUCTION:
            n = 11; break;

        case EXCEPTION_IN_PAGE_ERROR:
            n = 12; break;

        case EXCEPTION_INT_DIVIDE_BY_ZERO:
            n = 13; break;

        case EXCEPTION_INT_OVERFLOW:
            n = 14; break;

        case EXCEPTION_INVALID_DISPOSITION:
            n = 15; break;

        case EXCEPTION_NONCONTINUABLE_EXCEPTION:
            n = 16; break;

        case EXCEPTION_PRIV_INSTRUCTION:
            n = 17; break;

        case EXCEPTION_SINGLE_STEP:
            n = 18; break;

        case EXCEPTION_STACK_OVERFLOW:
            n = 19; break;
        }

        if (n >= 0)
            _tcsncpy(pszError, pszRTMsg[n], nSize);
        else if (nSize >= 32)
            _stprintf(pszError, _T("Unknown HRESULT = %08X\n"), m_hResult);
        else
            pszError[0] = '\0';
    }
}

int CException::ReportError(UINT type, LPCTSTR file, int line)
{
    TCHAR msg[512];
    TCHAR err[256];

    GetErrorMessage(err, 256);
    wsprintf(msg, _T("%s (l#%d)\n\n%s"), file, line, err);

    return ::MessageBox(NULL, msg, _T("Exception Error"), type);
}

//--------------------------------------------------------------------------;
// CMemoryException
//--------------------------------------------------------------------------;

CMemoryException::CMemoryException(void) 
    : CException(true, E_OUTOFMEMORY)
{
}

//--------------------------------------------------------------------------;
// CResourceException
//--------------------------------------------------------------------------;

CResourceException::CResourceException(void) 
    : CException(true, HRESULT_FROM_WIN32(ERROR_NO_SYSTEM_RESOURCES)) 
{
}

//--------------------------------------------------------------------------;
// CNotSupportedException
//--------------------------------------------------------------------------;

CNotImplementedException::CNotImplementedException(void) 
    : CException(true, E_NOTIMPL)
{
}

//--------------------------------------------------------------------------;
// Static exceptions
//--------------------------------------------------------------------------;

static CMemoryException         StaticMemoryException;
static CResourceException       StaticResourceException;
static CNotImplementedException StaticNotImplementedException;

void WINAPI ThrowException(HRESULT hResult)
{
    throw new CException(hResult);
}

void WINAPI ThrowException(int nError)
{
    throw new CException(HRESULT_FROM_WIN32(nError));
}

void WINAPI ThrowMemoryException(void)
{
    throw &StaticMemoryException;
}

void WINAPI ThrowResourceException(void)
{
    throw &StaticResourceException;
}

void WINAPI ThrowNotImplementedException(void)
{
    throw &StaticNotImplementedException;
}
