// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"

#ifdef AFX_CORE1_SEG
#pragma code_seg(AFX_CORE1_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// AFX_EXCEPTION_CONTEXT (thread global state)

inline AFX_EXCEPTION_CONTEXT* AfxGetExceptionContext()
{
	DWORD lError = GetLastError();
	AFX_EXCEPTION_CONTEXT* pContext = &_afxThreadState->m_exceptionContext;
	SetLastError(lError);
	return pContext;
}

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

CException::CException()
{
	// most exceptions are deleted when not needed
	m_bAutoDelete = TRUE;
#ifdef _DEBUG
	m_bReadyForDelete = FALSE;
#endif
}

CException::CException(BOOL bAutoDelete)
{
	// for exceptions which are not auto-delete (usually)
	m_bAutoDelete = bAutoDelete;
#ifdef _DEBUG
	m_bReadyForDelete = FALSE;
#endif
}

void CException::Delete()
{
	// delete exception if it is auto-deleting
	if (m_bAutoDelete > 0)
	{
#ifdef _DEBUG
		m_bReadyForDelete = TRUE;
#endif
		delete this;
	}
}

BOOL CException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
	PUINT pnHelpContext /* = NULL */ )
{
	if (pnHelpContext != NULL)
		*pnHelpContext = 0;

	if (nMaxError != 0 && lpszError != NULL)
		*lpszError = '\0';

	return FALSE;
}

int CException::ReportError(UINT nType /* = MB_OK */,
	UINT nError /* = 0 */)
{
	TCHAR   szErrorMessage[128];
	int     nDisposition;
	UINT    nHelpContext;

	if (GetErrorMessage(szErrorMessage, _countof(szErrorMessage), &nHelpContext))
		nDisposition = AfxMessageBox(szErrorMessage, nType, nHelpContext);
	else
	{
		if (nError == 0)
			nError = AFX_IDP_NO_ERROR_AVAILABLE;
		nDisposition = AfxMessageBox(nError, nType, nHelpContext);
	}
	return nDisposition;
}


#ifdef _DEBUG
void PASCAL CException::operator delete(void* pbData)
{
	// check for proper exception object deletion
	CException* pException = (CException*)pbData;
	// use: pException->Delete(), do not use: delete pException
	ASSERT(pException->m_bReadyForDelete);
	ASSERT(pException->m_bAutoDelete > 0);

	// avoid crash when assert above is ignored
	if (pException->m_bReadyForDelete && pException->m_bAutoDelete > 0)
		CObject::operator delete(pbData);
}
#endif

/////////////////////////////////////////////////////////////////////////////
// AFX_EXCEPTION_LINK linked 'jmpbuf' and out-of-line helpers

AFX_EXCEPTION_LINK::AFX_EXCEPTION_LINK()
{
	// setup initial link state
#ifdef _AFX_OLD_EXCEPTIONS
	m_nType = 0;
#endif
	m_pException = NULL;    // no current exception yet

	// wire into top of exception link stack
	AFX_EXCEPTION_CONTEXT* pContext = AfxGetExceptionContext();
	m_pLinkPrev = pContext->m_pLinkTop;
	pContext->m_pLinkTop = this;
}

// out-of-line cleanup called from inline AFX_EXCEPTION_LINK destructor
void AFXAPI AfxTryCleanup()
{
	AFX_EXCEPTION_CONTEXT* pContext = AfxGetExceptionContext();
	AFX_EXCEPTION_LINK* pLinkTop = pContext->m_pLinkTop;

	// delete current exception
	ASSERT(pLinkTop != NULL);
	if (pLinkTop->m_pException != NULL)
		pLinkTop->m_pException->Delete();

	// remove ourself from the top of the chain
	pContext->m_pLinkTop = pLinkTop->m_pLinkPrev;
}

#ifndef _AFX_OLD_EXCEPTIONS
// special out-of-line implementation of THROW_LAST (for auto-delete behavior)
void AFXAPI AfxThrowLastCleanup()
{
	AFX_EXCEPTION_CONTEXT* pContext = AfxGetExceptionContext();
	AFX_EXCEPTION_LINK* pLinkTop = pContext->m_pLinkTop;

	// check for THROW_LAST inside of auto-delete block
	if (pLinkTop != NULL)
	{
		// make sure current exception does not get auto-deleted
		pLinkTop->m_pException = NULL;
	}

	// THROW_LAST macro will do actual 'throw'
}
#endif //!_AFX_OLD_EXCEPTIONS

/////////////////////////////////////////////////////////////////////////////
// Global exception terminate handling - Obsolete API
//  (apps written to C++ exceptions should use set_terminate)

#ifdef _AFX_OLD_EXCEPTIONS

void AFXAPI AfxTerminate()
{
	TRACE0("AfxTerminate called.\n");
	(*AfxGetModuleProcessState()->m_pfnTerminate)();
}

AFX_TERM_PROC AFXAPI AfxSetTerminate(AFX_TERM_PROC pfnNew)
{
	AFX_MODULE_PROCESS_STATE* pState = AfxGetModuleProcessState();
	AFX_TERM_PROC pfnOld = pState->m_pfnTerminate;
	pState->m_pfnTerminate = pfnNew;
	return pfnOld;
}

#endif //_AFX_OLD_EXCEPTIONS

/////////////////////////////////////////////////////////////////////////////
// Special non-C++ exception implementation

#ifdef _AFX_OLD_EXCEPTIONS
// out-of-line implementation of THROW (for non-C++ exceptions)
void AFXAPI AfxThrow(CException* pNewException)
{
	// get current exception context for running task
	AFX_EXCEPTION_CONTEXT* pContext = AfxGetExceptionContext();

	// check for THROW_LAST() first
	if (pNewException == NULL)
	{
		ASSERT(pContext->m_pLinkTop != NULL);
		pNewException = pContext->m_pLinkTop->m_pException;
	}
	ASSERT_VALID(pNewException);

	TRACE1("Warning: Throwing an Exception of type %hs.\n",
		pNewException->GetRuntimeClass()->m_lpszClassName);

	while (pContext->m_pLinkTop != NULL)
	{
		AFX_EXCEPTION_LINK* pReceiver = pContext->m_pLinkTop;
		if (pReceiver->m_pException != NULL)
		{
			// a THROW during a CATCH block -- this link may not be
			//  destructed, so it is necessary to do all the cleanup that
			//  the destructor would do.
			if (pReceiver->m_pException != pNewException)
				pReceiver->m_pException->Delete();
			pReceiver->m_pException = NULL;
			pContext->m_pLinkTop = pReceiver->m_pLinkPrev;
		}
		else
		{
			// throw the exception to the top handler (if appropriate type)
			if (pReceiver->m_nType == 0)
			{
				// setup the receiver's context for the new exception
				pReceiver->m_pException = pNewException;

				// and jump into the handler...
				longjmp(pReceiver->m_jumpBuf, 1);
				ASSERT(FALSE);  // not reached
			}
			// otherwise just call cleanup proc
			(*pReceiver->m_callback.pfnCleanup)(pReceiver);
		}
	}

	ASSERT(pContext->m_pLinkTop == NULL);
	// uncaught exception, terminate
	TRACE1("Error: Uncaught Exception (%hs).\n",
		pNewException->GetRuntimeClass()->m_lpszClassName);
	AfxTerminate();
	ASSERT(FALSE);  // not reached
}

// out-of-line implementation of CATCH and AND_CATCH
BOOL AFXAPI AfxCatchProc(CRuntimeClass* pClass)
{
	ASSERT(pClass != NULL);

	AFX_EXCEPTION_CONTEXT* pContext = AfxGetExceptionContext();
	ASSERT(pContext->m_pLinkTop != NULL);
	CException* pException = pContext->m_pLinkTop->m_pException;
	ASSERT(pException != NULL);

	return pException->IsKindOf(pClass);
}
#endif //_AFX_OLD_EXCEPTIONS

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

IMPLEMENT_DYNAMIC(CException, CObject)

IMPLEMENT_DYNAMIC(CMemoryException, CException)
CMemoryException _simpleMemoryException(FALSE, AFX_IDS_MEMORY_EXCEPTION);

IMPLEMENT_DYNAMIC(CNotSupportedException, CException)
CNotSupportedException _simpleNotSupportedException(FALSE, AFX_IDS_NOT_SUPPORTED_EXCEPTION);

/////////////////////////////////////////////////////////////////////////////
// Standard exceptions

#ifdef AFX_AUX_SEG
#pragma code_seg(AFX_AUX_SEG)
#endif

void CSimpleException::InitString()
{
	m_bInitialized = TRUE;
	m_bLoaded = (AfxLoadString(m_nResourceID,
		m_szMessage, _countof(m_szMessage)) != 0);
}

BOOL CSimpleException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
		PUINT pnHelpContext)
{
	ASSERT(lpszError != NULL && AfxIsValidString(lpszError, nMaxError));

	if (pnHelpContext != NULL)
		*pnHelpContext = 0;

	// if we didn't load our string (eg, we're a console app)
	// return a null string and FALSE

	if (!m_bInitialized)
		InitString();

	if (m_bLoaded)
		lstrcpyn(lpszError, m_szMessage, nMaxError);
	else
		lpszError[0] = '\0';

	return m_bLoaded;
}


void AFXAPI AfxThrowMemoryException()
{
	THROW((CMemoryException*)&_simpleMemoryException);
}

void AFXAPI AfxThrowNotSupportedException()
{
	THROW((CNotSupportedException*)&_simpleNotSupportedException);
}

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

/////////////////////////////////////////////////////////////////////////////
