/******************************************************************************
 *                                                                         
 *               (C) COPYRIGHT Pacific MindWorks, Inc. 2001-2005
 *                          All rights reserved.
 *
 *****************************************************************************/

#ifndef __NTLBASE_INCLUDED
#define __NTLBASE_INCLUDED

#include <stdarg.h>
#include <atlrx.h>
#include <atlstr.h>
#include <atlcoll.h>
#include <atltrace.h>
#include <stack>
using namespace std;


////////////////////////////////////////////////////////////////////////////////
//
//	Forward declarations
//

template <class DriverClass, class IOProviderClass> class CDriver;
template <class DriverClass, class RootClass> class CDriverIOManager;
template <class RepCapClass, class RootClass, class ParentClass> class CRepCap;

///////////////////////////////////////////////////////////////
//
//   CObjectModelRootNode
//

// This macro allows us to "override" the _CreatorClass typedef in CComCoClass so that CObjectModelRootNode derives from the user's class
#define DECLARE_NIMBUS_CLASS(x) \
	typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< CObjectModelRootNode<x> > >, ATL::CComCreator< ATL::CComAggObject< CObjectModelRootNode<x> > > > _CreatorClass;

template <class NodeClass>
class CObjectModelRootNode : 
	public NodeClass
{
public:
	HRESULT FinalConstruct();
	void FinalRelease();

	HRESULT FinalInitialize(BSTR bstrResourceDescriptor, VARIANT_BOOL bIdQuery, VARIANT_BOOL bReset, BSTR bstrOptionString);
	HRESULT FinalInitialize(long lPerfObjectInstanceID, BSTR bstrPerfObjectInstanceName);		// For personality drivers
	HRESULT FinalClose();
};

template <class NodeClass>
HRESULT CObjectModelRootNode<NodeClass>::FinalConstruct()
{
	HRESULT hr = S_OK;

	hr = InternalFinalConstruct();

	// Call user's FinalConstruct
	if (SUCCEEDED(hr))
	{
		hr = NodeClass::FinalConstruct();
	}

	return hr;
}

template <class NodeClass>
void CObjectModelRootNode<NodeClass>::FinalRelease()
{

	// Call user's FinalRelease
	NodeClass* pNode = static_cast<NodeClass*>(this);
	pNode->FinalRelease();

	pNode->CloseEventServerManager();

	if (m_pRoot != NULL && m_pParent != NULL)	/* don't do Release on ourself */
	{
		m_pRoot->Release();
		m_pRoot = NULL;
	}

	if (m_pParent != NULL)
	{
		m_pParent->Release();
		m_pParent = NULL;
	}
}

template <class NodeClass>
HRESULT CObjectModelRootNode<NodeClass>::FinalInitialize(BSTR bstrResourceDescriptor, VARIANT_BOOL bIdQuery, VARIANT_BOOL bReset, BSTR bstrOptionString)
{
	HRESULT hr = S_OK;
	CComBSTR bstrDriverIdentifier;
	hr = IIviDriverIdentity_get_Identifier(&bstrDriverIdentifier);
	if (SUCCEEDED(hr))
	{
		CString strDriverIdentifier = COLE2T(bstrDriverIdentifier);
		hr = InitializePerfMonManager(strDriverIdentifier, GetResourceDescriptor());
		if (SUCCEEDED(hr))
		{
			hr = InitNode(this, NULL);
			if (SUCCEEDED(hr))
			{
				// Only execute the following code if the user has implemented a FinalInitialize
				__if_exists(NodeClass::FinalInitialize)
				{
					hr = NodeClass::FinalInitialize(bstrResourceDescriptor, bIdQuery, bReset, bstrOptionString);
				}
			}
		}
	}

	return hr;
}

template <class NodeClass>
HRESULT CObjectModelRootNode<NodeClass>::FinalInitialize(long lPerfObjectInstanceID, BSTR bstrPerfObjectInstanceName)
{
	HRESULT hr = S_OK;
	CString strPerfObjectInstanceName = COLE2T(bstrPerfObjectInstanceName);
	hr = InitializePerfMonManager(lPerfObjectInstanceID, strPerfObjectInstanceName);
	if (SUCCEEDED(hr))
	{
		hr = InitNode(this, NULL);
		if (SUCCEEDED(hr))
		{
			// Only execute the following code if the user has implemented a FinalInitialize
			__if_exists(NodeClass::FinalInitialize)
			{
				hr = NodeClass::FinalInitialize();
			}
		}
	}

	return hr;
}

template <class NodeClass>
HRESULT CObjectModelRootNode<NodeClass>::FinalClose()
{
	HRESULT hr = S_OK;

	// Only execute the following code if the user has implemented a FinalClose
	__if_exists(NodeClass::FinalClose)
	{
		hr = NodeClass::FinalClose();
	}

	if (SUCCEEDED(hr))
	{
		ClosePerfMonManager();

		hr = CloseNode();
	}

	return hr;
}

///////////////////////////////////////////////////////////////
//
//   CRepCapDescriptor
//

class CRepCapDescriptor
{ 
public:
	CRepCapDescriptor(const CString& strName, int nIndex, IUnknown* punk, void* pRepCap, CCacheManager* pCacheManager)
		: m_strInstanceName(strName), m_nInstanceIndex(nIndex), m_spUnk(punk), m_pRepCap(pRepCap), m_pCacheManager(pCacheManager)
	{}

public:
	const CString& GetInstanceName() const { return m_strInstanceName; }
	int GetInstanceIndex() const { return m_nInstanceIndex; }
	CComPtr<IUnknown> GetIUnknown() const { return m_spUnk; }
	void* GetRepCap() const { return m_pRepCap; }
	CCacheManager* GetCacheManager() const { return m_pCacheManager; }

	void SetInstanceIndex(int nInstanceIndex) { m_nInstanceIndex = nInstanceIndex; }

private:
	CString m_strInstanceName;
	int m_nInstanceIndex;
	CComPtr<IUnknown> m_spUnk;
	void* m_pRepCap;
	CCacheManager* m_pCacheManager;
};

///////////////////////////////////////////////////////////////
//
//   CObjectModelNodeBase
//

class CObjectModelNodeBase
{
public:
	virtual void InternalResetObjectState() = 0;
	virtual void ResetObjectState() = 0;

	virtual CString GetClassName() = 0;
	virtual void SetClassName(const CString& strClassName) = 0;

	virtual bool IsRoot() = 0;

	virtual CString GetInherentOptionValue(const CString& strName) = 0;
	virtual CString GetDriverSetupOptionValue(const CString& strName) = 0;

	virtual bool GetConfigSetting(const CString& strName, CComVariant& varValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, CString& strValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, int& nValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, double& dblValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, bool& bValue) = 0;

	virtual CString TranslateVirtualName(const CString& strVirtualName) = 0;
	virtual CString TranslatePhysicalName(const CString& strPhysicalName) = 0;

	virtual CString GetModel() = 0;
	virtual bool InstrumentSupported() = 0;
	virtual bool InstrumentInFamily(const CString& strFamily) = 0;
	virtual bool InstrumentIsModel(const CString& strModel) = 0;
	virtual bool ModelInFamily(const CString& strModel, const CString& strFamily) = 0;

	virtual bool GetActive() = 0;
	virtual HRESULT ActivatePersonality() = 0;
	virtual bool GetInitialized() = 0;

	virtual bool GetCache() = 0;
	virtual bool GetInterchangeCheck() = 0;
	virtual bool GetQueryInstrStatus() = 0;
	virtual bool GetRangeCheck() = 0;
	virtual bool GetRecordCoercions() = 0;
	virtual bool GetSimulate() = 0;

	virtual CString GetResourceDescriptor() = 0;
	virtual CString GetClientExeName() = 0;
	//virtual CTracer* GetTracer() = 0;
	virtual CString GetVisaDllFileName() = 0;
};

///////////////////////////////////////////////////////////////
//
//   CObjectModelNode
//

typedef CAtlArray<CRepCapDescriptor> RepCapDescriptorArray;
typedef CAtlArray<CString> RepCapNameArray;
typedef CAtlMap<CString, RepCapNameArray*> RepCapNameMap;					// key = repcap class name, value = array of repcap names
typedef CAtlMap<CString, RepCapDescriptorArray*> RepCapMap;					// key = repcap class name, value = RepCapDescriptorArray

template <class RepCapClass>
const CString& GetRepCapClassNameFromClass();							// Implemented in generated code

template <class NodeClass, class RootClass, class ParentClass>
class CObjectModelNode :
	public CObjectModelNodeBase,
	public CErrorManager<NodeClass>,
	public CDriverIOManager<NodeClass, RootClass>,
	public CEventServerManager,
	public CEnumCommandManager<NodeClass>,
	public CCacheManager,
	public CPerfMonManager,
	public CCallContextManager,
	public CCoercionLogManager,
	public CTraceManager
{
public:
	CObjectModelNode();
	virtual ~CObjectModelNode();

	virtual HRESULT InitNode(RootClass* pRoot, ParentClass* pParent);		// Implemented in generated code
	virtual HRESULT CloseNode();											// Implemented in generated code

	virtual void InternalResetObjectState();
	virtual void ResetObjectState();

	virtual CString GetClassName();
	virtual void SetClassName(const CString& strClassName);

	virtual RootClass* GetRoot();
	virtual void SetRoot(RootClass* pRoot);

	virtual bool IsRoot();

	virtual ParentClass* GetParent();
	virtual void SetParent(ParentClass* pParent);

	virtual HRESULT GetDynamicRepCapNames(const CString& repCapClassName, CAtlArray<CString>& rgRepCapNames);

	virtual CString GetInherentOptionValue(const CString& strName) = 0;
	virtual CString GetDriverSetupOptionValue(const CString& strName) = 0;

	virtual bool GetConfigSetting(const CString& strName, CComVariant& varValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, CString& strValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, int& nValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, double& dblValue) = 0;
	virtual bool GetConfigSetting(const CString& strName, bool& bValue) = 0;

	virtual CString TranslateVirtualName(const CString& strVirtualName) = 0;
	virtual CString TranslatePhysicalName(const CString& strPhysicalName) = 0;

	virtual CString GetModel() = 0;
	virtual bool InstrumentSupported();
	virtual bool InstrumentInFamily(const CString& strFamily);
	virtual bool InstrumentIsModel(const CString& strModel);
	virtual bool ModelInFamily(const CString& strModel, const CString& strFamily);

	virtual bool GetActive() = 0;
	virtual HRESULT ActivatePersonality() = 0;
	virtual bool GetInitialized() = 0;

	virtual bool GetCache() = 0;
	virtual bool GetInterchangeCheck() = 0;
	virtual bool GetQueryInstrStatus() = 0;
	virtual bool GetRangeCheck() = 0;
	virtual bool GetRecordCoercions() = 0;
	virtual bool GetSimulate() = 0;

	virtual CString GetResourceDescriptor() = 0;
	virtual CString GetClientExeName() = 0;
	//virtual CTracer* GetTracer() = 0;

	template <typename T>
	bool CacheContainsValue(const CString& strPath, T value)
	{
		bool bContainsValue = false;
		if (GetCache())
		{
			CCacheEntry<T>* pCacheEntry = GetOrCreateCacheEntry<T>(strPath);
			if (pCacheEntry != NULL)
			{
				bContainsValue = pCacheEntry->ContainsValue(value, GetModel(), this);
			}
		}

		return bContainsValue;
	}

	template <typename T>
	void UpdateCache(const CString& strPath, T value)
	{
		if (GetCache())
		{
			CCacheEntry<T>* pCacheEntry = GetOrCreateCacheEntry<T>(strPath);
			if (pCacheEntry != NULL)
			{
				pCacheEntry->UpdateValue(value);
			}
		}
	}

	template <typename T>
	bool GetCachedValue(const CString& strPath, T* pValue)
	{
		bool bFound = false;
		if (GetCache())
		{
			CCacheEntry<T>* pCacheEntry = GetOrCreateCacheEntry<T>(strPath);
			if (pCacheEntry != NULL)
			{
				bFound = pCacheEntry->GetValue(pValue, this);
			}
		}

		return bFound;
	}

	// Child repeated capability support
	template <typename RepCapClass>
	int GetRepCapCount()
	{
		int nCount = -1;

		CString strClassName = GetRepCapClassNameFromClass<RepCapClass>();

		NodeClass* pNode = static_cast<NodeClass*>(this);

		RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
		if (m_mapChildRepCaps.Lookup(strClassName, pRepCapDescriptorArray))
		{
			nCount = (int)pRepCapDescriptorArray->GetCount();
		}

		return nCount;
	}

	template <typename RepCapClass>
	RepCapClass* GetRepCap(const CString& strInstanceName)
	{
		CString strClassName = GetRepCapClassNameFromClass<RepCapClass>();

		NodeClass* pNode = static_cast<NodeClass*>(this);

		RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
		if (m_mapChildRepCaps.Lookup(strClassName, pRepCapDescriptorArray))
		{
			CString strPhysicalName = TranslateVirtualName(strInstanceName);
			bool bFound = false;
			for (UINT i = 0; i < pRepCapDescriptorArray->GetCount(); i++)
			{
				// Case-insensitive comparison
				CRepCapDescriptor repCapDesc = pRepCapDescriptorArray->GetAt(i);
				CString strName = repCapDesc.GetInstanceName();
				if (strPhysicalName.CompareNoCase(strName) == 0)
				{
					return reinterpret_cast<RepCapClass*>(repCapDesc.GetRepCap());
				}
			}
		}

		return NULL;
	}

	template <typename RepCapClass>
	RepCapClass* GetRepCap(int nIndex)
	{
		CString strClassName = GetRepCapClassNameFromClass<RepCapClass>();

		NodeClass* pNode = static_cast<NodeClass*>(this);

		RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
		if (m_mapChildRepCaps.Lookup(strClassName, pRepCapDescriptorArray))
		{
			if (nIndex < (int)pRepCapDescriptorArray->GetCount())
			{
				CRepCapDescriptor repCapDesc = pRepCapDescriptorArray->GetAt(nIndex);
				return reinterpret_cast<RepCapClass*>(repCapDesc.GetRepCap());
			}
		}

		return NULL;
	}

	template <class RepCapClass>
	HRESULT CreateChildNode(const CString& strRepCapClassName)
	{
		HRESULT hr = S_OK;

		// Populate the child repcap name map with all static repcap names
		RepCapNameArray* rgRepCapNames = new RepCapNameArray;
		const CString* pstrNames = CRepCap<RepCapClass, RootClass, NodeClass>::GetStaticRepCapNames();
		int i = 0;
		while (!pstrNames[i].IsEmpty())
		{
			rgRepCapNames->Add(pstrNames[i]);
			i++;
		}

		// Populate the child repcap name map with all dynamic repcap names
		RepCapNameArray rgDynamicRepNames;
		hr = GetDynamicRepCapNames(strRepCapClassName, rgDynamicRepNames);
		if (SUCCEEDED(hr))
		{
			for (i = 0; i < (int)rgDynamicRepNames.GetCount(); i++)
			{
				rgRepCapNames->Add(rgDynamicRepNames[i]);
			}

			// Create all the instances of this repeated capability
			RepCapDescriptorArray* pRepCapDescriptorArray = new RepCapDescriptorArray;
			for (i = 0; i < (int)rgRepCapNames->GetCount() && SUCCEEDED(hr); i++)
			{
				hr = CreateRepCapInstance<RepCapClass>(rgRepCapNames->GetAt(i), i, pRepCapDescriptorArray);
			}

			if (SUCCEEDED(hr))
			{
				m_mapChildRepCaps[strRepCapClassName] = pRepCapDescriptorArray;
			}
		}

		return hr;
	}

	template <class RepCapClass>
	HRESULT CreateRepCapInstance(const CString& strRepCapName, int nRepCapIndex, RepCapDescriptorArray* pRepCapDescriptorArray)
	{
		CComObject<RepCapClass>* pRepCap = NULL;
		HRESULT hr = CComObject<RepCapClass>::CreateInstance(&pRepCap);
		if (SUCCEEDED(hr))
		{
			CRepCapDescriptor newRepCap(strRepCapName, nRepCapIndex, pRepCap->GetUnknown(), pRepCap, static_cast<CCacheManager*>(pRepCap));
			pRepCapDescriptorArray->Add(newRepCap);

			pRepCap->SetInstanceName(strRepCapName);
			pRepCap->SetInstanceIndex(nRepCapIndex);

			hr = pRepCap->InitNode(m_pRoot, static_cast<NodeClass*>(this));
			if (SUCCEEDED(hr))
			{
				IIviEventServer* pEventServer = NULL;
				m_pRoot->GetEventServer(&pEventServer);
				hr = pRepCap->InitializeEventServerManager(pEventServer, m_pRoot->GetSourceCookie(), m_pRoot->GetSinkCookie());
				if (SUCCEEDED(hr))
				{
					hr = pRepCap->InitializePerfMonManager(m_pRoot->GetPerformanceObjectInstanceID(), m_pRoot->GetPerformanceObjectInstanceName());
				}
			}
		}

		return hr;
	}

	template <class RepCapClass>
	HRESULT DeleteChildNode(const CString& strRepCapClassName)
	{
		HRESULT hr = S_OK;

		RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
		m_mapChildRepCaps.Lookup(strRepCapClassName, pRepCapDescriptorArray);
		ATLASSERT(pRepCapDescriptorArray != NULL);
		if (pRepCapDescriptorArray != NULL)
		{
			for (UINT i = 0; i < pRepCapDescriptorArray->GetCount() && SUCCEEDED(hr); i++)
			{
				CRepCapDescriptor repCapDescriptor = pRepCapDescriptorArray->GetAt(i);
				hr = reinterpret_cast<RepCapClass*>(repCapDescriptor.GetRepCap())->CloseNode();
			}

			delete pRepCapDescriptorArray;
		}

		return hr;
	}

	template <class RepCapClass>
	HRESULT AddRepCapItem(const CString& strRepCapClassName, BSTR bstrRepCapName)
	{
		HRESULT hr = S_OK;

		RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
		if (!m_mapChildRepCaps.Lookup(strRepCapClassName, pRepCapDescriptorArray))
			return E_UNEXPECTED;

		// Next available index
		int nRepCapIndex = pRepCapDescriptorArray->GetCount();

		hr = CreateRepCapInstance<RepCapClass>(LPCTSTR(COLE2T(bstrRepCapName)), nRepCapIndex, pRepCapDescriptorArray);

		return hr;
	}

	template <class RepCapClass>
	HRESULT RemoveRepCapItem(const CString& strRepCapClassName, BSTR bstrRepCapName)
	{
		HRESULT hr = S_OK;

		NodeClass* pNode = static_cast<NodeClass*>(this);

		CString strItem = COLE2T(bstrRepCapName);

		RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
		if (!m_mapChildRepCaps.Lookup(strRepCapClassName, pRepCapDescriptorArray))
			return E_UNEXPECTED;

		CString strPhysicalName = TranslateVirtualName(strItem);
		bool bFound = false;
		for (UINT i = 0; i < pRepCapDescriptorArray->GetCount(); i++)
		{
			// Case-insensitive comparison
			CRepCapDescriptor repCapDesc = pRepCapDescriptorArray->GetAt(i);
			CString strName = repCapDesc.GetInstanceName();
			if (strPhysicalName.CompareNoCase(strName) == 0)
			{
				// We have found our item

				// Decrement by 1 the instance index of all the instances that follow
				// the instance we are about to remove
				for (UINT j = i + 1; j < pRepCapDescriptorArray->GetCount(); j++)
				{
					CRepCapDescriptor& repCapDesc2 = pRepCapDescriptorArray->GetAt(j);
					int nUpdatedInstanceIndex = repCapDesc2.GetInstanceIndex() - 1;
					
					repCapDesc2.SetInstanceIndex(nUpdatedInstanceIndex);
					((RepCapClass*)repCapDesc2.GetRepCap())->SetInstanceIndex(nUpdatedInstanceIndex);
				}

				pRepCapDescriptorArray->RemoveAt(i);

				bFound = true;
				break;
			}
		}

		if (!bFound)
			hr = pNode->ReportError(IDS_E_IVI_UNKNOWN_PHYSICAL_IDENTIFIER);

		return hr;
	}

	HRESULT GetRepCapItemCount(const CString& strRepCap, long* plCount);
	HRESULT GetRepCapItemName(const CString& strRepCap, long lIndex, BSTR* pbstrName);

	template <class ItfType>
	HRESULT GetRepCapItem(const CString& strRepCap, CComBSTR bstrItem, ItfType** ppRepCap)
	{
		if (ppRepCap == NULL)
			return E_POINTER;
		*ppRepCap = NULL;

		HRESULT hr = S_OK;

		NodeClass* pNode = static_cast<NodeClass*>(this);

		CString strItem = COLE2T(bstrItem);

		RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
		if (!m_mapChildRepCaps.Lookup(strRepCap, pRepCapDescriptorArray))
			return E_UNEXPECTED;

		CString strPhysicalName = TranslateVirtualName(strItem);
		bool bFound = false;
		for (UINT i = 0; i < pRepCapDescriptorArray->GetCount(); i++)
		{
			// Case-insensitive comparison
			CRepCapDescriptor repCapDesc = pRepCapDescriptorArray->GetAt(i);
			CString strName = repCapDesc.GetInstanceName();
			if (strPhysicalName.CompareNoCase(strName) == 0)
			{
				bFound = true;
				hr = repCapDesc.GetIUnknown()->QueryInterface(ppRepCap);
				break;
			}
		}

		if (!bFound)
			hr = pNode->ReportError(IDS_E_IVI_UNKNOWN_PHYSICAL_IDENTIFIER);

		return hr;
	}

#ifdef NTL_MANAGED_CPP_EXTENSIONS
	typedef Int32 Int32Array __gc[];
	typedef double DoubleArray __gc[];

	HRESULT ConvertSystemArrayToSAFEARRAY(double data __gc[], SAFEARRAY** ppsa);
	HRESULT ConvertSystemArrayToSAFEARRAY(Int32 data __gc[], SAFEARRAY** ppsa);

	HRESULT ConvertSAFEARRAYToSystemArray(SAFEARRAY* psa, DoubleArray* data);
	HRESULT ConvertSAFEARRAYToSystemArray(SAFEARRAY* psa, Int32Array* data);
#endif // NTL_MANAGED_CPP_EXTENSIONS

protected:
	virtual CCacheManager* GetRepCapCacheManager(const CString& strRepCapName, long lRepCapIndex);
	virtual CCacheManager* GetRootCacheManager();
	virtual void InvalidateRepCapCache();

protected:
	CString m_strClassName;
	RootClass* m_pRoot;
	ParentClass* m_pParent;
	RepCapMap m_mapChildRepCaps;
	stack<CCallContext*> m_driverCallStack;
};

template <class NodeClass, class RootClass, class ParentClass>
CObjectModelNode<NodeClass, RootClass, ParentClass>::CObjectModelNode()
	: CCoercionLogManager(this), m_pRoot(NULL), m_pParent(NULL)
{
}

template <class NodeClass, class RootClass, class ParentClass>
CObjectModelNode<NodeClass, RootClass, ParentClass>::~CObjectModelNode()
{
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelNode<NodeClass, RootClass, ParentClass>::InternalResetObjectState()
{
	ResetObjectState();

	POSITION pos = m_mapChildRepCaps.GetStartPosition();
	while (pos != NULL)
	{
		RepCapDescriptorArray* pRepCapDescriptorArray = m_mapChildRepCaps.GetNextValue(pos);
		for (int i = 0; i < (int)pRepCapDescriptorArray->GetCount(); i++)
		{
			CRepCapDescriptor repCapDescriptor = pRepCapDescriptorArray->GetAt(i);
			reinterpret_cast<CObjectModelNodeBase*>(repCapDescriptor.GetRepCap())->InternalResetObjectState();
		}
	}
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelNode<NodeClass, RootClass, ParentClass>::ResetObjectState()
{
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelNode<NodeClass, RootClass, ParentClass>::GetClassName()
{
	return m_strClassName;
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelNode<NodeClass, RootClass, ParentClass>::SetClassName(const CString& strClassName)
{
	m_strClassName = strClassName;
}

template <class NodeClass, class RootClass, class ParentClass>
RootClass* CObjectModelNode<NodeClass, RootClass, ParentClass>::GetRoot()
{
	return m_pRoot;
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelNode<NodeClass, RootClass, ParentClass>::SetRoot(RootClass* pRoot)
{
	if (m_pRoot != pRoot)
	{
		if (m_pRoot != NULL && !IsRoot())
			m_pRoot->Release();

		m_pRoot = pRoot;

		if (m_pRoot != NULL && !IsRoot())	/* don't AddRef on ourself */
			m_pRoot->AddRef();
	}
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelNode<NodeClass, RootClass, ParentClass>::IsRoot()
{
	return (dynamic_cast<RootClass*>(this) != m_pRoot);
}

template <class NodeClass, class RootClass, class ParentClass>
ParentClass* CObjectModelNode<NodeClass, RootClass, ParentClass>::GetParent()
{
	return m_pParent;
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelNode<NodeClass, RootClass, ParentClass>::SetParent(ParentClass* pParent)
{
	if (m_pParent != pParent)
	{
		if (m_pParent != NULL)
			m_pParent->Release();

		m_pParent = pParent;

		if (m_pParent != NULL)
			m_pParent->AddRef();
	}
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelNode<NodeClass, RootClass, ParentClass>::GetDynamicRepCapNames(const CString& repCapClassName, CAtlArray<CString>& rgRepCapNames)
{
	NTL_UNUSED(repCapClassName);
	NTL_UNUSED(rgRepCapNames);

	return S_OK;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelNode<NodeClass, RootClass, ParentClass>::GetRepCapItemCount(const CString& strRepCap, long* plCount)
{
	if (plCount == NULL)
		return E_POINTER;

	HRESULT hr = S_OK;

	RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
	if (!m_mapChildRepCaps.Lookup(strRepCap, pRepCapDescriptorArray))
		return E_UNEXPECTED;

	*plCount = (long)pRepCapDescriptorArray->GetCount();

	return hr;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelNode<NodeClass, RootClass, ParentClass>::GetRepCapItemName(const CString& strRepCap, long lIndex, BSTR* pbstrName)
{
	if (pbstrName == NULL)
		return E_POINTER;

	HRESULT hr = S_OK;
	
	RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
	if (!m_mapChildRepCaps.Lookup(strRepCap, pRepCapDescriptorArray))
		return E_UNEXPECTED;

	// NOTE: IVI-COM indexing is 1-based
	if ((lIndex < 1) || (lIndex > (long)pRepCapDescriptorArray->GetCount()))
		return ReportInvalidValueError(_T("get_Name"), _T("Index"), lIndex);

	CString strName = TranslatePhysicalName(pRepCapDescriptorArray->GetAt(lIndex - 1).GetInstanceName());

	*pbstrName = ::SysAllocString(CT2OLE(strName));

	return hr;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelNode<NodeClass, RootClass, ParentClass>::InstrumentSupported()
{
	bool bRet = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		const InstrModelMap* pModelMap = CInstrumentModelManager::GetModelMap();
		CString strModel = GetModel();
		CString strFamily;
		bRet = pModelMap->Lookup(strModel, strFamily);
	}

	return bRet;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelNode<NodeClass, RootClass, ParentClass>::InstrumentInFamily(const CString& strFamily)
{
	bool bRet = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		CString strModel = GetModel();
		bRet = ModelInFamily(strModel, strFamily);
	}

	return bRet;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelNode<NodeClass, RootClass, ParentClass>::InstrumentIsModel(const CString& strModel)
{
	bool bRet = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		bRet = GetModel() == strModel;
	}

	return bRet;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelNode<NodeClass, RootClass, ParentClass>::ModelInFamily(const CString& strModel, const CString& strFamily)
{
	bool bRet = false;
	InstrModelMap* pModelMap = NULL;
	if (CInstrumentModelManager::GetFamilyMap()->Lookup(strFamily, pModelMap))
	{
		CString strFamilyDummy;
		bRet = pModelMap->Lookup(strModel, strFamilyDummy);
	}

	return bRet;
}

template <class NodeClass, class RootClass, class ParentClass>
CCacheManager* CObjectModelNode<NodeClass, RootClass, ParentClass>::GetRepCapCacheManager(const CString& strRepCapName, long lRepCapIndex)
{
	CCacheManager* pCacheManager = NULL;
	RepCapDescriptorArray* pRepCapDescriptorArray = NULL;
	if (m_mapChildRepCaps.Lookup(strRepCapName, pRepCapDescriptorArray))
	{
		if (lRepCapIndex < (long)pRepCapDescriptorArray->GetCount())
		{
			CRepCapDescriptor repCapDescriptor = pRepCapDescriptorArray->GetAt(lRepCapIndex);
			pCacheManager = repCapDescriptor.GetCacheManager();
		}
	}

	return pCacheManager;
}

template <class NodeClass, class RootClass, class ParentClass>
CCacheManager* CObjectModelNode<NodeClass, RootClass, ParentClass>::GetRootCacheManager()
{
	CCacheManager* pCacheManager = NULL;
	RootClass* pRoot = GetRoot();
	if (pRoot != NULL)
	{
		pCacheManager = static_cast<CCacheManager*>(pRoot);
	}

	return pCacheManager;
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelNode<NodeClass, RootClass, ParentClass>::InvalidateRepCapCache()
{
	POSITION pos = m_mapChildRepCaps.GetStartPosition();
	while (pos != NULL)
	{
		RepCapDescriptorArray* pRepCapDescriptorArray = m_mapChildRepCaps.GetNextValue(pos);
		for (int i = 0; i < (int)pRepCapDescriptorArray->GetCount(); i++)
		{
			CRepCapDescriptor repCapDescriptor = pRepCapDescriptorArray->GetAt(i);
			repCapDescriptor.GetCacheManager()->InvalidateCache();
		}
	}
}

#ifdef NTL_MANAGED_CPP_EXTENSIONS
template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelNode<NodeClass, RootClass, ParentClass>::ConvertSystemArrayToSAFEARRAY(double data __gc[], SAFEARRAY** ppsa)
{
	HRESULT hr = S_OK;

	if (data != NULL)
	{
		SAFEARRAY* psa = ::SafeArrayCreateVector(VT_R8, 0, data->Length);
		if (psa != NULL)
		{
			void* pvData = NULL;
			hr = ::SafeArrayAccessData(psa, &pvData);
			if (SUCCEEDED(hr))
			{
				IntPtr dest(pvData);
				Runtime::InteropServices::Marshal::Copy(data, 0, dest, data->Length);
				::SafeArrayUnaccessData(psa);

				*ppsa = psa;
			}
		}
		else
		{
			hr = ReportError(IDS_E_IVI_OUT_OF_MEMORY);
		}
	}
	else
	{
		*ppsa = NULL;
	}

	return hr;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelNode<NodeClass, RootClass, ParentClass>::ConvertSystemArrayToSAFEARRAY(Int32 data __gc[], SAFEARRAY** ppsa)
{
	HRESULT hr = S_OK;

	if (data != NULL)
	{
		SAFEARRAY* psa = ::SafeArrayCreateVector(VT_I4, 0, data->Length);
		if (psa != NULL)
		{
			void* pvData = NULL;
			hr = ::SafeArrayAccessData(psa, &pvData);
			if (SUCCEEDED(hr))
			{
				IntPtr dest(pvData);
				Runtime::InteropServices::Marshal::Copy(data, 0, dest, data->Length);
				::SafeArrayUnaccessData(psa);

				*ppsa = psa;
			}
		}
		else
		{
			hr = ReportError(IDS_E_IVI_OUT_OF_MEMORY);
		}
	}
	else
	{
		*ppsa = NULL;
	}

	return hr;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelNode<NodeClass, RootClass, ParentClass>::ConvertSAFEARRAYToSystemArray(SAFEARRAY* psa, DoubleArray* data)
{
	HRESULT hr = S_OK;

	if (psa != NULL)
	{
		int nLowerBound;
		int nCount;
		hr = GetSafeArrayVectorSizeInfo(psa, &nLowerBound, &nCount);
		if (SUCCEEDED(hr))
		{
			void* pvData = NULL;
			hr = ::SafeArrayAccessData(psa, &pvData);
			if (SUCCEEDED(hr))
			{
				IntPtr src(pvData);
				double dest __gc[] = new double __gc[nCount];

				Runtime::InteropServices::Marshal::Copy(src, dest, nLowerBound, nCount);

				*data = dest;

				::SafeArrayUnaccessData(psa);
			}
		}
	}
	else
	{
		*data = NULL;
	}

	return hr;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelNode<NodeClass, RootClass, ParentClass>::ConvertSAFEARRAYToSystemArray(SAFEARRAY* psa, Int32Array* data)
{
	HRESULT hr = S_OK;

	if (psa != NULL)
	{
		int nLowerBound;
		int nCount;
		hr = GetSafeArrayVectorSizeInfo(psa, &nLowerBound, &nCount);
		if (SUCCEEDED(hr))
		{
			void* pvData = NULL;
			hr = ::SafeArrayAccessData(psa, &pvData);
			if (SUCCEEDED(hr))
			{
				IntPtr src(pvData);
				Int32 dest __gc[] = new Int32 __gc[nCount];

				Runtime::InteropServices::Marshal::Copy(src, dest, nLowerBound, nCount);

				*data = dest;

				::SafeArrayUnaccessData(psa);
			}
		}
	}
	else
	{
		*data = NULL;
	}

	return hr;
}
#endif // NTL_MANAGED_CPP_EXTENSIONS

///////////////////////////////////////////////////////////////////////////////
//
//	CObjectModelRootNodeBase
//

template <class NodeClass, class IOProviderClass>
class CObjectModelRootNodeBase : 
	public IOProviderClass,
	public CObjectModelNode<NodeClass, NodeClass, NodeClass>
{
public:
	CObjectModelRootNodeBase();
	virtual ~CObjectModelRootNodeBase();

protected:
	virtual HRESULT InternalFinalConstruct() = 0;

public:
	void SetIdentificationInfo(const CString& strIdentification, const CString& strManufacturer, const CString& strModel, const CString& strSerialNumber, const CString& strFirmwareRevision); 

	virtual CString GetInherentOptionValue(const CString& strName);
	virtual CString GetDriverSetupOptionValue(const CString& strName);

	virtual bool GetConfigSetting(const CString& strName, CComVariant& varValue);
	virtual bool GetConfigSetting(const CString& strName, CString& strValue);
	virtual bool GetConfigSetting(const CString& strName, int& nValue);
	virtual bool GetConfigSetting(const CString& strName, double& dblValue);
	virtual bool GetConfigSetting(const CString& strName, bool& bValue);

	virtual HRESULT BuildVirtualNameMaps(IIviDriverSessionPtr spDriverSession);
	virtual CString TranslatePhysicalName(const CString& strPhysicalName);
	virtual CString TranslateVirtualName(const CString& strVirtualName);

	virtual CString GetModel();
	virtual CString GetSerialNumber();

	virtual bool GetActive();
	virtual HRESULT ActivatePersonality();
	virtual bool GetInitialized();

	virtual bool GetCache();
	virtual bool GetInterchangeCheck();
	virtual bool GetQueryInstrStatus();
	virtual bool GetRangeCheck();
	virtual bool GetRecordCoercions();
	virtual bool GetSimulate();

	virtual CString GetResourceDescriptor();
	virtual CString GetClientExeName();

	// CCallContextManager overrides
	virtual CCallContext* GetCallContext();
	virtual void PushCallContext(CCallContext* pCallContext);
	virtual CCallContext* PopCallContext();
	virtual CString GetRepeatedCapabilityIdentifier();

	void SetWrappedDriver(CDriverWrapper* pWrappedDriver);

protected:
	bool m_bCache;
	bool m_bInterchangeCheck;
	bool m_bQueryInstrStatus;
	bool m_bRangeCheck;
	bool m_bRecordCoercions;
	bool m_bSimulate;

	bool m_bCacheOriginal;
	bool m_bInterchangeCheckOriginal;
	bool m_bQueryInstrStatusOriginal;
	bool m_bRangeCheckOriginal;
	bool m_bRecordCoercionsOriginal;
	bool m_bSimulateOriginal;

	bool m_bInitialized; 
	bool m_bIdentificationInitialized;

	CString m_strInitOptionString;
	CString m_strLogicalName;
	CString m_strResourceDescriptor;
	CString m_strDriverSetup;
	CString m_strManufacturer;
	CString m_strModel;
	CString m_strSerialNumber;
	CString m_strFirmwareRevision;
	CString m_strIdentification;

	CAtlMap<CString, CString> m_mapInherentOptions;
	CAtlMap<CString, CString> m_mapDriverSetupOptions;
	CAtlMap<CString, CComVariant> m_mapConfigSettings;
	CAtlMap<CString, CString> m_mapVirtualToPhysicalNames;
	CAtlMap<CString, CString> m_mapPhysicalToVirtualNames;

	CString m_strClientExeName;

	CDriverWrapper* m_pWrappedDriver;
};

template <class NodeClass, class IOProviderClass>
CObjectModelRootNodeBase<NodeClass, IOProviderClass>::CObjectModelRootNodeBase()
{
	m_bCache = true;				// IVI-defined default value
	m_bInterchangeCheck = false;	// IVI-defined default value
	m_bQueryInstrStatus = false;	// IVI-defined default value
	m_bRangeCheck = true;			// IVI-defined default value
	m_bRecordCoercions = false;		// IVI-defined default value
	m_bSimulate = false;			// IVI-defined default value

	m_bInitialized = false;
	m_bIdentificationInitialized = false;

	m_pWrappedDriver = NULL;

	// Retrieve the name of the executable file for the client process
	TCHAR szFileName[MAX_PATH];
	HMODULE hProcess = ::GetModuleHandle(NULL);
	DWORD nFileNameLenActual = ::GetModuleFileName(hProcess, szFileName, MAX_PATH);
	if (nFileNameLenActual != 0)
	{
		CPath strPath = szFileName;
		strPath.StripPath();
		m_strClientExeName = (CString)strPath;
	}
	else
	{
		// Function failed, so just use a default name
		m_strClientExeName = "Unknown.exe";
	}
}

template <class NodeClass, class IOProviderClass>
CObjectModelRootNodeBase<NodeClass, IOProviderClass>::~CObjectModelRootNodeBase()
{
}

template <class NodeClass, class IOProviderClass>
void CObjectModelRootNodeBase<NodeClass, IOProviderClass>::SetIdentificationInfo(
	const CString& strIdentification, 
	const CString& strManufacturer,
	const CString& strModel,
	const CString& strSerialNumber,
	const CString& strFirmwareRevision) 
{ 
	NodeClass* pT = static_cast<NodeClass*>(this);

	pT->m_strIdentification = strIdentification;
	pT->m_strManufacturer = strManufacturer;
	pT->m_strModel = strModel;
	pT->m_strSerialNumber = strSerialNumber;
	pT->m_strFirmwareRevision = strFirmwareRevision;

	pT->m_bIdentificationInitialized = true;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetInherentOptionValue(const CString& strName)
{
	CString strOptionName = strName;
	strOptionName.MakeLower();

	CString strValue;
	m_mapInherentOptions.Lookup(strOptionName, strValue);
	
	return strValue;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetDriverSetupOptionValue(const CString& strName)
{
	CString strOptionName = strName;
	strOptionName.MakeLower();

	CString strValue;
	m_mapDriverSetupOptions.Lookup(strOptionName, strValue);
	
	return strValue;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetConfigSetting(const CString& strName, CComVariant& varValue)
{
	CString strLowerName = strName;
	strLowerName.MakeLower();

	bool bFound = m_mapConfigSettings.Lookup(strLowerName, varValue);

	return bFound;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetConfigSetting(const CString& strName, CString& strValue)
{
	CComVariant varValue;
	bool bFound = GetConfigSetting(strName, varValue);
	if (bFound)
	{
		bFound = varValue.vt == VT_BSTR;
		if (bFound)
		{
			strValue = COLE2T(varValue.bstrVal);
		}
	}

	return bFound;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetConfigSetting(const CString& strName, int& nValue)
{
	CComVariant varValue;
	bool bFound = GetConfigSetting(strName, varValue);
	if (bFound)
	{
		bFound = varValue.ChangeType(VT_I4) == S_OK;
		if (bFound)
		{
			nValue = varValue.intVal;
		}
	}

	return bFound;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetConfigSetting(const CString& strName, double& dblValue)
{
	CComVariant varValue;
	bool bFound = GetConfigSetting(strName, varValue);
	if (bFound)
	{
		bFound = varValue.ChangeType(VT_R8) == S_OK;
		if (bFound)
		{
			dblValue = varValue.dblVal;
		}
	}

	return bFound;
}

template <class NodeClass, class IOProviderClass>
bool  CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetConfigSetting(const CString& strName, bool& bValue)
{
	CComVariant varValue;
	bool bFound = GetConfigSetting(strName, varValue);
	if (bFound)
	{
		bFound = varValue.ChangeType(VT_BOOL) == S_OK;
		if (bFound)
		{
			bValue = varValue.boolVal != VARIANT_FALSE;
		}
	}

	return bFound;
}

template <class NodeClass, class IOProviderClass>
HRESULT CObjectModelRootNodeBase<NodeClass, IOProviderClass>::BuildVirtualNameMaps(IIviDriverSessionPtr spDriverSession)
{
	HRESULT hr = S_OK;

	m_mapVirtualToPhysicalNames.RemoveAll();
	m_mapPhysicalToVirtualNames.RemoveAll();	

	IIviVirtualNameCollectionPtr spVirtualNames = spDriverSession->VirtualNames;
	for (long nVirtualName = 0; nVirtualName < spVirtualNames->Count; nVirtualName++)
	{
		IIviVirtualNamePtr spVirtualName = spVirtualNames->GetItem(nVirtualName + 1);
		_bstr_t bstrVirtualName = spVirtualName->Name;
		_bstr_t bstrMapTo = spVirtualName->MapTo;
		IIviVirtualRangeCollectionPtr spVirtualRanges = spVirtualName->VirtualRanges;
		if (spVirtualRanges->Count == 0)
		{
			CString strVirtualName = COLE2T(bstrVirtualName);
			strVirtualName.MakeLower();

			CString strMapTo = COLE2T(bstrMapTo);
			strMapTo.MakeLower();

			m_mapVirtualToPhysicalNames[strVirtualName] = strMapTo;
			m_mapPhysicalToVirtualNames[strMapTo] = strVirtualName;
		}
		else
		{
			for (long nVirtualRange = 0; nVirtualRange < spVirtualRanges->Count; nVirtualRange++)
			{
				IIviVirtualRangePtr spVirtualRange = spVirtualRanges->GetItem(nVirtualRange + 1);
				for (long nVirtualRangeVal = spVirtualRange->Min; nVirtualRangeVal <= spVirtualRange->Max; nVirtualRangeVal++)
				{
					// Convert to lowercase (comparison is always done lowercase)
					CString strVirtualNameTemp = COLE2T(bstrVirtualName);
					CString strVirtualName;
					strVirtualName.Format(_T("%s%d"), strVirtualNameTemp, nVirtualRangeVal);
					strVirtualName.MakeLower();

					CString strMapToTemp = COLE2T(bstrMapTo);
					CString strPhysicalName;
					strPhysicalName.Format(_T("%s%d"), strMapToTemp, nVirtualRangeVal + spVirtualRange->StartingPhysicalIndex - spVirtualRange->Min);
					strPhysicalName.MakeLower();

					m_mapVirtualToPhysicalNames[strVirtualName] = strPhysicalName;
					m_mapPhysicalToVirtualNames[strPhysicalName] = strVirtualName;
				}

				// Convert to lowercase (comparison is always done lowercase)
				CString strVirtualName = COLE2T(bstrVirtualName);
				strVirtualName.MakeLower();

				CString strPhysicalName = COLE2T(bstrMapTo);
				strPhysicalName.MakeLower();

				m_mapVirtualToPhysicalNames[strVirtualName] = strPhysicalName;
				m_mapPhysicalToVirtualNames[strPhysicalName] = strVirtualName;
			}
		}
	}

	return hr;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::TranslateVirtualName(const CString& strVirtualName)
{
	CString strName = strVirtualName;
	strName.MakeLower();

	CString strPhysicalName;
	if (!m_mapVirtualToPhysicalNames.Lookup(strName, strPhysicalName))
	{
		// Virtual name not found, so use physical name is the same as the virtual name
		strPhysicalName = strVirtualName;
	}

	return strPhysicalName;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::TranslatePhysicalName(const CString& strPhysicalName)
{
	CString strName = strPhysicalName;
	strName.MakeLower();

	CString strVirtualName;
	if (!m_mapPhysicalToVirtualNames.Lookup(strName, strVirtualName))
	{
		// Physical name not found, so virtual name is the same as the physical name
		strVirtualName = strPhysicalName;
	}

	return strVirtualName;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetActive()
{
	return true;
}

template <class NodeClass, class IOProviderClass>
HRESULT CObjectModelRootNodeBase<NodeClass, IOProviderClass>::ActivatePersonality()
{
	return S_OK;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetInitialized()
{
	return m_bInitialized;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetCache()
{
	return m_bCache;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetInterchangeCheck()
{
	return m_bInterchangeCheck;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetQueryInstrStatus()
{
	return m_bQueryInstrStatus;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetRangeCheck()
{
	return m_bRangeCheck;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetRecordCoercions()
{
	return m_bRecordCoercions;
}

template <class NodeClass, class IOProviderClass>
bool CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetSimulate()
{
	return m_bSimulate;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetModel()
{
	CString strModel;
	if (GetInitialized())
	{
		strModel = m_strModel;
	}

	return strModel;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetSerialNumber()
{
	return m_strSerialNumber;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetResourceDescriptor()
{
	return m_strResourceDescriptor;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetClientExeName()
{
	return m_strClientExeName;
}

template <class NodeClass, class IOProviderClass>
CCallContext* CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetCallContext()
{
	CCallContext* pCallContext = NULL;
	if (!m_driverCallStack.empty())
	{
		pCallContext = m_driverCallStack.top();
	}

	return pCallContext;
}

template <class NodeClass, class IOProviderClass>
void CObjectModelRootNodeBase<NodeClass, IOProviderClass>::PushCallContext(CCallContext* pCallContext)
{
	m_driverCallStack.push(pCallContext);
}

template <class NodeClass, class IOProviderClass>
CCallContext* CObjectModelRootNodeBase<NodeClass, IOProviderClass>::PopCallContext()
{
	CCallContext* pCallContext = GetCallContext();
	m_driverCallStack.pop();

	return pCallContext;
}

template <class NodeClass, class IOProviderClass>
CString CObjectModelRootNodeBase<NodeClass, IOProviderClass>::GetRepeatedCapabilityIdentifier()
{
	return _T("");
}

template <class NodeClass, class IOProviderClass>
void CObjectModelRootNodeBase<NodeClass, IOProviderClass>::SetWrappedDriver(CDriverWrapper* pWrappedDriver)
{
	m_pWrappedDriver = pWrappedDriver;
}

///////////////////////////////////////////////////////////////////////////////
//
//	CObjectModelChildNode
//

template <class NodeClass, class RootClass, class ParentClass>
class CObjectModelChildNode :
	public CObjectModelNode<NodeClass, RootClass, ParentClass>
{
public:
	CObjectModelChildNode();
	virtual ~CObjectModelChildNode();

    void SetInstanceName(const CString& strName);
	CString GetInstanceName();

	void SetInstanceIndex(int nIndex);
	int GetInstanceIndex();

public:
	virtual CString GetInherentOptionValue(const CString& strName);
	virtual CString GetDriverSetupOptionValue(const CString& strName);

	virtual bool GetConfigSetting(const CString& strName, CComVariant& varValue);
	virtual bool GetConfigSetting(const CString& strName, CString& strValue);
	virtual bool GetConfigSetting(const CString& strName, int& nValue);
	virtual bool GetConfigSetting(const CString& strName, double& dblValue);
	virtual bool GetConfigSetting(const CString& strName, bool& bValue);

	virtual CString TranslateVirtualName(const CString& strVirtualName);
	virtual CString TranslatePhysicalName(const CString& strPhysicalName);

	virtual CString GetModel();

	virtual bool GetActive();
	virtual HRESULT ActivatePersonality();
	virtual bool GetInitialized();

	virtual bool GetCache();
	virtual bool GetInterchangeCheck();
	virtual bool GetQueryInstrStatus();
	virtual bool GetRangeCheck();
	virtual bool GetRecordCoercions();
	virtual bool GetSimulate();

	virtual CString GetResourceDescriptor();
	virtual CString GetClientExeName();

	// CDriverIOManager overrides
	virtual HRESULT InitializeIOManager(BSTR bstrResourceDescriptor);
	virtual HRESULT CloseIOManager();

	// CTraceManager overrides
	virtual CTracer* GetTracer();

	// CCallContextManager overrides
	virtual CCallContext* GetCallContext();
	virtual void PushCallContext(CCallContext* pCallContext);
	virtual CCallContext* PopCallContext();
	virtual CString GetRepeatedCapabilityIdentifier();

protected:
    CString m_strInstanceName;
	int m_nInstanceIndex;
	CString m_strRepeatedCapabilityIdentifier;
};

template <class NodeClass, class RootClass, class ParentClass>
CObjectModelChildNode<NodeClass, RootClass, ParentClass>::CObjectModelChildNode()
	: m_nInstanceIndex(0)
{
}

template <class NodeClass, class RootClass, class ParentClass>
CObjectModelChildNode<NodeClass, RootClass, ParentClass>::~CObjectModelChildNode()
{
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelChildNode<NodeClass, RootClass, ParentClass>::SetInstanceName(const CString& strName)
{
	m_strInstanceName = strName;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetInstanceName()
{
	return m_strInstanceName;
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelChildNode<NodeClass, RootClass, ParentClass>::SetInstanceIndex(int nIndex)
{
	m_nInstanceIndex = nIndex;
}

template <class NodeClass, class RootClass, class ParentClass>
int CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetInstanceIndex()
{
	return m_nInstanceIndex;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetInherentOptionValue(const CString& strOptionName)
{
	CString strValue;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		strValue = GetRoot()->GetInherentOptionValue(strOptionName);
	}

	return strValue;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetDriverSetupOptionValue(const CString& strOptionName)
{
	CString strValue;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		strValue = GetRoot()->GetDriverSetupOptionValue(strOptionName);
	}

	return strValue;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetConfigSetting(const CString& strName, CComVariant& varValue)
{
	bool bFound = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		bFound = GetRoot()->GetConfigSetting(strName, varValue);
	}

	return bFound;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetConfigSetting(const CString& strName, CString& strValue)
{
	bool bFound = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		bFound = GetRoot()->GetConfigSetting(strName, strValue);
	}

	return bFound;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetConfigSetting(const CString& strName, int& nValue)
{
	bool bFound = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		bFound = GetRoot()->GetConfigSetting(strName, nValue);
	}

	return bFound;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetConfigSetting(const CString& strName, double& dblValue)
{
	bool bFound = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		bFound = GetRoot()->GetConfigSetting(strName, dblValue);
	}

	return bFound;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetConfigSetting(const CString& strName, bool& bValue)
{
	bool bFound = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		bFound = GetRoot()->GetConfigSetting(strName, bValue);
	}

	return bFound;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::TranslateVirtualName(const CString& strVirtualName)
{
	CString strPhysicalName;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		strPhysicalName = GetRoot()->TranslateVirtualName(strVirtualName);
	}

	return strPhysicalName;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::TranslatePhysicalName(const CString& strPhysicalName)
{
	CString strVirtualName;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		strVirtualName = GetRoot()->TranslateVirtualName(strPhysicalName);
	}

	return strVirtualName;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetModel()
{
	CString strModel;
	if (GetInitialized())
	{
		strModel = GetRoot()->GetModel();
	}

	return strModel;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetActive()
{
	bool bRet = false;
	if (GetInitialized())
	{
		bRet = GetRoot()->GetActive();
	}

	return bRet;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelChildNode<NodeClass, RootClass, ParentClass>::ActivatePersonality()
{
	HRESULT hr = E_FAIL;

	if (GetInitialized())
	{
		hr = GetRoot()->ActivatePersonality();
	}

	return hr;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetInitialized()
{
	return (GetRoot() != NULL);
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetCache()
{
	bool b = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{ 
		b = GetRoot()->GetCache();
	}

	return b;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetInterchangeCheck()
{
	bool b = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{ 
		b = GetRoot()->GetInterchangeCheck();
	}

	return b;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetQueryInstrStatus()
{
	bool b = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{ 
		b = GetRoot()->GetQueryInstrStatus();
	}

	return b;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetRangeCheck()
{
	bool b = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{ 
		b = GetRoot()->GetRangeCheck();
	}

	return b;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetRecordCoercions()
{
	bool b = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{ 
		b = GetRoot()->GetRecordCoercions();
	}

	return b;
}

template <class NodeClass, class RootClass, class ParentClass>
bool CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetSimulate()
{
	bool b = false;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{ 
		b = GetRoot()->GetSimulate();
	}

	return b;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetResourceDescriptor()
{
	CString strResourceDescriptor;
	if (GetInitialized())
	{
		strResourceDescriptor = GetRoot()->GetResourceDescriptor();
	}

	return strResourceDescriptor;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetClientExeName()
{
	CString strClientExeName;
	if (GetInitialized())
	{
		strClientExeName = GetRoot()->GetClientExeName();
	}

	return strClientExeName;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelChildNode<NodeClass, RootClass, ParentClass>::InitializeIOManager(BSTR bstrResourceDescriptor)
{
	NTL_UNUSED(bstrResourceDescriptor);

	return S_OK;
}

template <class NodeClass, class RootClass, class ParentClass>
HRESULT CObjectModelChildNode<NodeClass, RootClass, ParentClass>::CloseIOManager()
{
	return S_OK;
}

template <class NodeClass, class RootClass, class ParentClass>
CTracer* CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetTracer()
{
	CTracer* pTracer = NULL;
	if (GetInitialized())
	{
		pTracer = GetRoot()->GetTracer();
	}

	return pTracer;
}

template <class NodeClass, class RootClass, class ParentClass>
CCallContext* CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetCallContext()
{
	CCallContext* pCallContext = NULL;
	if (GetInitialized())
	{
		pCallContext = GetRoot()->GetCallContext();
	}

	return pCallContext;
}

template <class NodeClass, class RootClass, class ParentClass>
void CObjectModelChildNode<NodeClass, RootClass, ParentClass>::PushCallContext(CCallContext* pCallContext)
{
	if (GetInitialized())
	{
		GetRoot()->PushCallContext(pCallContext);
	}
}

template <class NodeClass, class RootClass, class ParentClass>
CCallContext* CObjectModelChildNode<NodeClass, RootClass, ParentClass>::PopCallContext()
{
	CCallContext* pCallContext = NULL;
	if (GetInitialized())
	{
		pCallContext = GetRoot()->PopCallContext();
	}

	return pCallContext;
}

template <class NodeClass, class RootClass, class ParentClass>
CString CObjectModelChildNode<NodeClass, RootClass, ParentClass>::GetRepeatedCapabilityIdentifier()
{
	// This string is lazy-initialized
	if (m_strRepeatedCapabilityIdentifier == _T(""))
	{
		// Format is, for example:  <ParentRepCapIdentifier>.Agilent54600Trace[trace1]
		CString strParentRepCapIdentifier = GetParent()->GetRepeatedCapabilityIdentifier();
		if (strParentRepCapIdentifier != _T(""))
		{
			strParentRepCapIdentifier += _T(".");
		}

		m_strRepeatedCapabilityIdentifier.Format(_T("%s%s[%s]"), strParentRepCapIdentifier, GetClassName(), TranslatePhysicalName(GetInstanceName()));
	}

	return m_strRepeatedCapabilityIdentifier;
}

///////////////////////////////////////////////////////////////////////////////
//
//	CDriver
//

template <class DriverClass, class IOProviderClass>
class CDriver :
	public CObjectModelRootNodeBase<DriverClass, IOProviderClass>,
	public IIviDriverImpl<DriverClass>
{
public:
	CDriver();
	~CDriver();

	// IIviDriverIdentity helpers
	virtual const CString& GetDescription();							// Overridden in generated code
	virtual const CString& GetRevision();								// Overridden in generated code
	virtual const CString& GetVendor();									// Overridden in generated code
	virtual const CString& GetGroupCapabilities();						// Overridden in generated code
	virtual const CString& GetIdentifier();								// Overridden in generated code
	virtual long GetSpecificationMajorVersion();						// Overridden in generated code
	virtual long GetSpecificationMinorVersion();						// Overridden in generated code

	virtual CString GetVisaDllFileName();								// Overridden in generated code

	virtual CEventServerSource* CreateSource();							// Overridden in generated code
	virtual CEventServerSink* CreateSink();								// Overridden in generated code
	virtual const _EVENTSERVER_LOCATION_INFO* GetLocationInfo() const;	// Overridden in generated code

	virtual HRESULT InternalFinalConstruct();

	// CCoercionLogManager overrides
	virtual CCoercionLog* GetCoercionLog();

	// CTraceManager overrides
	virtual CTracer* GetTracer();
	virtual MSXML2::IXMLDOMElementPtr GetCurrentTraceElement();
	virtual void SetCurrentTraceElement(MSXML2::IXMLDOMElementPtr spCurrentElement);
	virtual HRESULT CommitTraceData();

	virtual HRESULT InitializeTraceManager();
	virtual HRESULT SetTraceEnabled(VARIANT_BOOL val);
	virtual HRESULT GetTraceEnabled(VARIANT_BOOL* val);

	friend class IIviDriverImpl<DriverClass>;
protected:
	CCoercionLog* m_pCoercionLog;
	CTraceOwner* m_pTracer;
};

template <class DriverClass, class IOProviderClass>
CDriver<DriverClass, IOProviderClass>::CDriver()
{
	m_pCoercionLog = new CCoercionLog();
	m_pTracer = new CTraceOwner();
}

template <class DriverClass, class IOProviderClass>
CDriver<DriverClass, IOProviderClass>::~CDriver()
{
	if (m_pCoercionLog != NULL)
		delete m_pCoercionLog;

	if (m_pTracer != NULL)
		delete m_pTracer;
}

template <class DriverClass, class IOProviderClass>
HRESULT CDriver<DriverClass, IOProviderClass>::InternalFinalConstruct()
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);

	CComBSTR bstrDriverIdentifier;
	hr = pT->IIviDriverIdentity_get_Identifier(&bstrDriverIdentifier);
	if (SUCCEEDED(hr))
	{
		CString strDriverIdentifier = COLE2T(bstrDriverIdentifier);
		hr = InitializeEventServerManager(strDriverIdentifier);
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
CCoercionLog* CDriver<DriverClass, IOProviderClass>::GetCoercionLog()
{
	return m_pCoercionLog;
}

template <class DriverClass, class IOProviderClass>
CTracer* CDriver<DriverClass, IOProviderClass>::GetTracer()
{
	return m_pTracer;
}

template <class DriverClass, class IOProviderClass>
MSXML2::IXMLDOMElementPtr CDriver<DriverClass, IOProviderClass>::GetCurrentTraceElement()
{
	return m_pTracer->GetCurrentElement();
}

template <class DriverClass, class IOProviderClass>
void CDriver<DriverClass, IOProviderClass>::SetCurrentTraceElement(MSXML2::IXMLDOMElementPtr spCurrentElement)
{
	ATLASSERT(m_pTracer != NULL);
	if (m_pTracer != NULL)
	{
		m_pTracer->SetCurrentElement(spCurrentElement);
	}
}

template <class DriverClass, class IOProviderClass>
HRESULT CDriver<DriverClass, IOProviderClass>::CommitTraceData()
{
	HRESULT hr = S_OK;

	ATLASSERT(m_pTracer != NULL);
	if (m_pTracer != NULL)
	{
		hr = m_pTracer->CommitTraceData();
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
HRESULT CDriver<DriverClass, IOProviderClass>::InitializeTraceManager()
{
	DriverClass* pT = static_cast<DriverClass*>(this);

	HRESULT hr = S_OK;

	ATLASSERT(m_pTracer != NULL);
	if (m_pTracer != NULL)
	{
		if (m_pTracer->GetTraceEnabled())
		{
			CString strDriverIdentifier;
			CComBSTR bstrDriverIdentifier;
			hr = pT->IIviDriverIdentity_get_Identifier(&bstrDriverIdentifier);
			if (SUCCEEDED(hr))
			{
				strDriverIdentifier = COLE2T(bstrDriverIdentifier);
				hr = m_pTracer->StartTrace(strDriverIdentifier, m_pTracer->GetTraceName());
			}
		}
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
HRESULT CDriver<DriverClass, IOProviderClass>::SetTraceEnabled(VARIANT_BOOL val)
{
	HRESULT hr = S_OK;

	ATLASSERT(m_pTracer != NULL);
	if (m_pTracer != NULL)
	{
		if (val != VARIANT_FALSE)
		{
			// Setting it to on:
			// If it's already enabled, set the trace state to Running
			// If it's not enabled, call m_pTracer->SetTraceEnabled, and then InitializeTraceManager
			if (m_pTracer->GetTraceEnabled())
			{
				if (m_pTracer->GetTraceState() != TraceStateDataFull)
				{
					m_pTracer->SetTraceState(TraceStateRunning);
				}
			}
			else
			{
				m_pTracer->SetTraceEnabled(true);
				hr = InitializeTraceManager();
			}
		}
		else
		{
			// Setting it to off:
			// If it's already enabled, set the trace state to Stopped
			// If it's not enabled, nothing to do
			if (m_pTracer->GetTraceOn())
			{
				m_pTracer->SetTraceState(TraceStateStopped);
			}
			else
			{
				// Nothing to do
			}
		}
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
HRESULT CDriver<DriverClass, IOProviderClass>::GetTraceEnabled(VARIANT_BOOL* val)
{
	HRESULT hr = S_OK;

	ATLASSERT(m_pTracer != NULL);
	if (m_pTracer != NULL)
	{
		*val = m_pTracer->GetTraceOn() ? VARIANT_TRUE : VARIANT_FALSE;
	}
	
	return hr;
}

///////////////////////////////////////////////////////////////////////////////
//
//	CRepCap
//

template <class RepCapClass, class RootClass, class ParentClass>
class CRepCap :
	public CObjectModelChildNode<RepCapClass, RootClass, ParentClass>
{
public:
	static const CString* GetStaticRepCapNames();		// Implemented in generated code

	virtual CString GetVisaDllFileName();								

	// CCoercionLogManager overrides
	virtual CCoercionLog* GetCoercionLog();

	// CTraceManager overrides
	virtual CTracer* GetTracer();
	virtual MSXML2::IXMLDOMElementPtr GetCurrentTraceElement();
	virtual void SetCurrentTraceElement(MSXML2::IXMLDOMElementPtr spCurrentElement);
	virtual HRESULT CommitTraceData();
};

template <class RepCapClass, class RootClass, class ParentClass>
CString CRepCap<RepCapClass, RootClass, ParentClass>::GetVisaDllFileName()
{
	CString strFileName;
	ATLASSERT(GetInitialized());
	if (GetInitialized())
	{
		strFileName = GetRoot()->GetVisaDllFileName();
	}

	return strFileName;
}

template <class RepCapClass, class RootClass, class ParentClass>
CCoercionLog* CRepCap<RepCapClass, RootClass, ParentClass>::GetCoercionLog()
{
	CCoercionLog* pCoercionLog = NULL;
	if (GetInitialized())
	{
		pCoercionLog = GetRoot()->GetCoercionLog();
	}

	return pCoercionLog;
}

template <class RepCapClass, class RootClass, class ParentClass>
CTracer* CRepCap<RepCapClass, RootClass, ParentClass>::GetTracer()
{
	CTracer* pTracer = NULL;
	if (GetInitialized())
	{
		pTracer = GetRoot()->GetTracer();
	}

	return pTracer;
}

template <class RepCapClass, class RootClass, class ParentClass>
MSXML2::IXMLDOMElementPtr CRepCap<RepCapClass, RootClass, ParentClass>::GetCurrentTraceElement()
{
	MSXML2::IXMLDOMElementPtr spCurrentElement;
	if (GetInitialized())
	{
		spCurrentElement = GetRoot()->GetCurrentTraceElement();
	}

	return spCurrentElement;
}

template <class RepCapClass, class RootClass, class ParentClass>
void CRepCap<RepCapClass, RootClass, ParentClass>::SetCurrentTraceElement(MSXML2::IXMLDOMElementPtr spCurrentElement)
{
	if (GetInitialized())
	{
		GetRoot()->SetCurrentTraceElement(spCurrentElement);
	}
}

template <class RepCapClass, class RootClass, class ParentClass>
HRESULT CRepCap<RepCapClass, RootClass, ParentClass>::CommitTraceData()
{
	HRESULT hr = S_OK;
	if (GetInitialized())
	{
		hr = GetRoot()->CommitTraceData();
	}

	return hr;
}

////////////////////////////////////////////////////////////////////////
//
//	Nimbus trace category
//

CTraceCategory NIMBUS_CATEGORY(_T("Nimbus"));

////////////////////////////////////////////////////////////////////////
//
//	Method level macros
//

#define NTL_CHECK_ACTIVE() \
	if (!pT->GetInitialized()) \
	{ \
		return pT->ReportError(IDS_E_IVI_NOT_INITIALIZED); \
	} \
	if (!pT->GetActive()) \
	{ \
		if (FAILED(pT->ActivatePersonality())) \
		{ \
			return pT->ReportError(GetDriverErrorResourceId(NTL_IDS_PERSONALITY_NOT_ACTIVE)); \
		} \
	} \

#define NTL_CHECK_INITIALIZED() \
	if (!pT->GetInitialized()) \
	{ \
		return pT->ReportError(IDS_E_IVI_NOT_INITIALIZED); \
	} \

#define NTL_OBJECT_LOCK() \
	Deriving::ObjectLock lock(pT);

#define NTL_METHOD_START_INIT_NOT_REQUIRED(InterfaceName, MethodName) \
	CErrorHelper errorHelper(pT, __uuidof(InterfaceName)); \
    SetErrorInfo(0, NULL);

#define NTL_METHOD_START_INIT_REQUIRED(InterfaceName, MethodName) \
	CErrorHelper errorHelper(pT, __uuidof(InterfaceName)); \
	NTL_CHECK_INITIALIZED(); \
	NTL_CHECK_ACTIVE(); \
	SetErrorInfo(0, NULL); \
	pT->IncrementMethodCallCount();

#define NTL_METHOD_START(InterfaceName, MethodName) \
	NTL_METHOD_START_INIT_REQUIRED(InterfaceName, MethodName);

#endif // __NTLBASE_INCLUDED
