// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1997 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

/////////////////////////////////////////////////////////////////////////////
// Runtime Typing

// special runtime-class structure for CObject (no base class)
#ifdef _AFXDLL
CRuntimeClass* PASCAL CObject::_GetBaseClass()
	{ return NULL; }
const AFX_DATADEF struct CRuntimeClass CObject::classCObject =
	{ "CObject", sizeof(CObject), 0xffff, NULL, &CObject::_GetBaseClass, NULL };
#else
const AFX_DATADEF struct CRuntimeClass CObject::classCObject =
	{ "CObject", sizeof(CObject), 0xffff, NULL, NULL, NULL };
#endif

CRuntimeClass* CObject::GetRuntimeClass() const
{
	return RUNTIME_CLASS(CObject);
}

BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
	ASSERT(this != NULL);
	// it better be in valid memory, at least for CObject size
	ASSERT(AfxIsValidAddress(this, sizeof(CObject)));

	// simple SI case
	CRuntimeClass* pClassThis = GetRuntimeClass();
	return pClassThis->IsDerivedFrom(pClass);
}

CObject* AFX_CDECL AfxDynamicDownCast(CRuntimeClass* pClass, CObject* pObject)
{
	if (pObject != NULL && pObject->IsKindOf(pClass))
		return pObject;
	else
		return NULL;
}

#ifdef _DEBUG
CObject* AFX_CDECL AfxStaticDownCast(CRuntimeClass* pClass, CObject* pObject)
{
	ASSERT(pObject == NULL || pObject->IsKindOf(pClass));
	return pObject;
}
#endif

/////////////////////////////////////////////////////////////////////////////
// Diagnostic Support

#ifdef _DEBUG
void AFXAPI AfxAssertValidObject(const CObject* pOb,
	LPCSTR lpszFileName, int nLine)
{
	if (pOb == NULL)
	{
		TRACE0("ASSERT_VALID fails with NULL pointer.\n");
		if (AfxAssertFailedLine(lpszFileName, nLine))
			AfxDebugBreak();
		return;     // quick escape
	}
	if (!AfxIsValidAddress(pOb, sizeof(CObject)))
	{
		TRACE0("ASSERT_VALID fails with illegal pointer.\n");
		if (AfxAssertFailedLine(lpszFileName, nLine))
			AfxDebugBreak();
		return;     // quick escape
	}

	// check to make sure the VTable pointer is valid
	ASSERT(sizeof(CObject) == sizeof(void*));
	if (!AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE))
	{
		TRACE0("ASSERT_VALID fails with illegal vtable pointer.\n");
		if (AfxAssertFailedLine(lpszFileName, nLine))
			AfxDebugBreak();
		return;     // quick escape
	}

	if (!AfxIsValidAddress(pOb, pOb->GetRuntimeClass()->m_nObjectSize, FALSE))
	{
		TRACE0("ASSERT_VALID fails with illegal pointer.\n");
		if (AfxAssertFailedLine(lpszFileName, nLine))
			AfxDebugBreak();
		return;     // quick escape
	}
	pOb->AssertValid();
}

void CObject::AssertValid() const
{
	ASSERT(this != NULL);
}

void CObject::Dump(CDumpContext& dc) const
{
	dc << "a " << GetRuntimeClass()->m_lpszClassName <<
		" at " << (void*)this << "\n";

	UNUSED(dc); // unused in release build
}
#endif //_DEBUG

////////////////////////////////////////////////////////////////////////////
// Allocation/Creation

CObject* CRuntimeClass::CreateObject()
{
	if (m_pfnCreateObject == NULL)
	{
		TRACE(_T("Error: Trying to create object which is not ")
			  _T("DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n"),
			m_lpszClassName);
		return NULL;
	}

	CObject* pObject = NULL;
	TRY
	{
		pObject = (*m_pfnCreateObject)();
	}
	END_TRY

	return pObject;
}

////////////////////////////////////////////////////////////////////////////
// Class loader & class serialization

BOOL CObject::IsSerializable() const
{
	return (GetRuntimeClass()->m_wSchema != 0xffff);
}

AFX_CLASSINIT::AFX_CLASSINIT(register CRuntimeClass* pNewClass)
{
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
	AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
	pModuleState->m_classList.AddHead(pNewClass);
	AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
}

BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const
{
	ASSERT(this != NULL);
	ASSERT(AfxIsValidAddress(this, sizeof(CRuntimeClass), FALSE));
	ASSERT(pBaseClass != NULL);
	ASSERT(AfxIsValidAddress(pBaseClass, sizeof(CRuntimeClass), FALSE));

	// simple SI case
	const CRuntimeClass* pClassThis = this;
	while (pClassThis != NULL)
	{
		if (pClassThis == pBaseClass)
			return TRUE;
#ifdef _AFXDLL
		pClassThis = (*pClassThis->m_pfnGetBaseClass)();
#else
		pClassThis = pClassThis->m_pBaseClass;
#endif
	}
	return FALSE;       // walked to the top, no match
}

////////////////////////////////////////////////////////////////////////////
// CRuntimeClass special diagnostics

#ifdef _DEBUG
void AFXAPI AfxDoForAllClasses(void (AFX_CDECL *pfn)(const CRuntimeClass*, void*),
	void* pContext)
{
	// just walk through the simple list of registered classes
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
	AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
	for (CRuntimeClass* pClass = pModuleState->m_classList; pClass != NULL;
		pClass = pClass->m_pNextClass)
	{
		(*pfn)(pClass, pContext);
	}
	AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
#ifdef _AFXDLL
	// walk through the list of dynlink library registered classes
	AfxLockGlobals(CRIT_DYNLINKLIST);
	for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;
		pDLL = pDLL->m_pNextDLL)
	{
		for (pClass = pDLL->m_classList; pClass != NULL;
			pClass = pClass->m_pNextClass)
		{
			(*pfn)(pClass, pContext);
		}
	}
	AfxUnlockGlobals(CRIT_DYNLINKLIST);
#endif
}
#endif //_DEBUG

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