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

#ifndef __NTLPERSONALITY_INCLUDED
#define __NTLPERSONALITY_INCLUDED

#include <atlcoll.h>

#import "IviConfigServer.dll" no_namespace

////////////////////////////////////////////////////////////////////////
//
//	Constants
//

// CATID required for all personalities
// {293577A9-C29C-4c10-A034-F8B4574C0EFB}
static const CATID CATID_IVI_COM_DRIVER_PERSONALITY = 
{ 0x293577a9, 0xc29c, 0x4c10, { 0xa0, 0x34, 0xf8, 0xb4, 0x57, 0x4c, 0xe, 0xfb } };


///////////////////////////////////////////////////////////////////////////////
//
//	IPersonalityDispatchImpl
//

enum
{
	// Initialization methods called from personality host
	DISPID_INITIALIZE_PERSONALITY = 1,
	DISPID_INITIALIZE_PERSONALITY_VISACOM_IO_PROVIDER,
	DISPID_INITIALIZE_PERSONALITY_VISA_IO_PROVIDER,
	DISPID_INITIALIZE_PERSONALITY_NULL_IO_PROVIDER,
	DISPID_INITIALIZE_PERSONALITY_CUSTOM_IO_PROVIDER,
	DISPID_FINAL_INITIALIZE_PERSONALITY,

	// Activation methods called from personality host
	DISPID_SELECT_PERSONALITY,
	DISPID_DESELECT_PERSONALITY,

	// IIviDriver methods called from personality host
	DISPID_CLOSE,

	// IIviDriverUtility methods called from personality host
	DISPID_DISABLE,
	DISPID_LOCKOBJECT,
	DISPID_RESET,
	DISPID_RESET_WITH_DEFAULTS,
	DISPID_UNLOCK_OBJECT,

	// IIviDriverOperation methods called from personality host
	DISPID_CACHE,
	DISPID_INTERCHANGE_CHECK,
	DISPID_QUERY_INSTRUMENT_STATUS,
	DISPID_RECORD_COERCIONS,
	DISPID_RANGE_CHECK,
	DISPID_SIMULATE,
	DISPID_INVALIDATE_ALL_ATTRIBUTES,
	DISPID_RESET_INTERCHANGE_CHECK,

	DISPID_SET_TRACER_STATE,
};

typedef CAtlMap<CString, DISPID>	DISPIDMap;			// key = function name, value = DISPID

template <class DriverClass>
class IPersonalityDispatchImpl :
	public IDispatch
{
public:
	IPersonalityDispatchImpl();
	virtual ~IPersonalityDispatchImpl();

	// IDispatch
	STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
	STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
	STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid);
	STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr);

private:
	DISPIDMap m_mapDISPIDs;
};

template <class DriverClass>
IPersonalityDispatchImpl<DriverClass>::IPersonalityDispatchImpl()
{
	// Initialization methods called from personality host
	m_mapDISPIDs["InitializePersonality"]					=	DISPID_INITIALIZE_PERSONALITY;
	m_mapDISPIDs["InitializePersonalityVisaComIOProvider"]	=	DISPID_INITIALIZE_PERSONALITY_VISACOM_IO_PROVIDER;
	m_mapDISPIDs["InitializePersonalityVisaIOProvider"]		=	DISPID_INITIALIZE_PERSONALITY_VISA_IO_PROVIDER;
	m_mapDISPIDs["InitializePersonalityNullIOProvider"]		=	DISPID_INITIALIZE_PERSONALITY_NULL_IO_PROVIDER;
	m_mapDISPIDs["InitializePersonalityCustomIOProvider"]	=	DISPID_INITIALIZE_PERSONALITY_CUSTOM_IO_PROVIDER;
	m_mapDISPIDs["FinalInitializePersonality"]				=	DISPID_FINAL_INITIALIZE_PERSONALITY;

	// Activation methods called from personality host
	m_mapDISPIDs["SelectPersonality"]						=	DISPID_SELECT_PERSONALITY;
	m_mapDISPIDs["DeSelectPersonality"]						=	DISPID_DESELECT_PERSONALITY;

	// IIviDriver methods called from personality host
	m_mapDISPIDs["Close"]									=	DISPID_CLOSE;

	// IIviDriverUtility methods called from personality host
	m_mapDISPIDs["Disable"]									=	DISPID_DISABLE;
	m_mapDISPIDs["LockObject"]								=	DISPID_LOCKOBJECT;
	m_mapDISPIDs["Reset"]									=	DISPID_RESET;
	m_mapDISPIDs["ResetWithDefaults"]						=	DISPID_RESET_WITH_DEFAULTS;
	m_mapDISPIDs["UnlockObject"]							=	DISPID_UNLOCK_OBJECT;

	// IIviDriverOperation methods called from personality host
	m_mapDISPIDs["Cache"]									=	DISPID_CACHE;
	m_mapDISPIDs["InterchangeCheck"]						=	DISPID_INTERCHANGE_CHECK;
	m_mapDISPIDs["QueryInstrumentStatus"]					=	DISPID_QUERY_INSTRUMENT_STATUS;
	m_mapDISPIDs["RecordCoercions"]							=	DISPID_RECORD_COERCIONS;
	m_mapDISPIDs["RangeCheck"]								=	DISPID_RANGE_CHECK;
	m_mapDISPIDs["Simulate"]								=	DISPID_SIMULATE;
	m_mapDISPIDs["InvalidateAllAttributes"]					=	DISPID_INVALIDATE_ALL_ATTRIBUTES;
	m_mapDISPIDs["ResetInterchangeCheck"]					=	DISPID_RESET_INTERCHANGE_CHECK;

	m_mapDISPIDs["SetTracerState"]							=	DISPID_SET_TRACER_STATE;
}

template <class DriverClass>
IPersonalityDispatchImpl<DriverClass>::~IPersonalityDispatchImpl()
{
}

template <class DriverClass>
STDMETHODIMP IPersonalityDispatchImpl<DriverClass>::GetTypeInfoCount(UINT* pctinfo)
{
	// We do not support type information for our IDispatch
	*pctinfo = 0;

	return S_OK;
}

template <class DriverClass>
STDMETHODIMP IPersonalityDispatchImpl<DriverClass>::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
	if (!pptinfo)
		return E_POINTER;
	*pptinfo = NULL;

	// We do not support type information for our IDispatch
	return DISP_E_BADINDEX;
}

template <class DriverClass>
STDMETHODIMP IPersonalityDispatchImpl<DriverClass>::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
	NTL_UNUSED(riid);
	NTL_UNUSED(lcid);

	ATLASSERT(rgdispid);
	if (!rgdispid)
		return E_POINTER;

	ATLASSERT(cNames == 1);
	if (cNames != 1)
		return E_UNEXPECTED;

	HRESULT hr = S_OK;

	DISPID dispid;
	if (m_mapDISPIDs.Lookup(COLE2T(rgszNames[0]), dispid))
	{
		rgdispid[0] = dispid;
	}
	else
	{
		ATLASSERT(false);
		rgdispid[0] = DISPID_UNKNOWN;
		hr = DISP_E_MEMBERNOTFOUND;
	}

	return hr;
}

template <class DriverClass>
STDMETHODIMP IPersonalityDispatchImpl<DriverClass>::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
	NTL_UNUSED(lcid);
	NTL_UNUSED(wFlags);
	NTL_UNUSED(pvarResult);
	NTL_UNUSED(pexcepinfo);
	NTL_UNUSED(puArgErr);

	if (riid != IID_NULL)
		return DISP_E_UNKNOWNINTERFACE;

	HRESULT hr = S_OK;

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

	switch (dispid)
	{
		// Initialization methods called from personality host
		case DISPID_INITIALIZE_PERSONALITY:
		{
			ATLASSERT(pdispparams->cArgs == 24);
			if (pdispparams->cArgs != 24)
				return DISP_E_BADPARAMCOUNT;

			IIviEventServer* pEventServer = NULL;
			hr = pdispparams->rgvarg[4].punkVal->QueryInterface(__uuidof(pEventServer), (void**)&pEventServer);
			ATLASSERT(SUCCEEDED(hr));
			if (SUCCEEDED(hr))
			{
				IIviDriverSession* pDriverSession = NULL;
				if (pdispparams->rgvarg[10].punkVal != NULL)
				{
					hr = pdispparams->rgvarg[10].punkVal->QueryInterface(__uuidof(pDriverSession), (void**)&pDriverSession);
				}

				if (SUCCEEDED(hr))
				{
					hr = pT->InitializePersonality(
						pdispparams->rgvarg[0].punkVal,
						pdispparams->rgvarg[1].bstrVal,
						pdispparams->rgvarg[2].bstrVal,
						pdispparams->rgvarg[3].bstrVal,
						pEventServer,
						pdispparams->rgvarg[5].lVal,
						pdispparams->rgvarg[6].lVal,
						pdispparams->rgvarg[7].lVal,
						pdispparams->rgvarg[8].bstrVal,
						pdispparams->rgvarg[9].bstrVal,
						pDriverSession,
						pdispparams->rgvarg[11].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[12].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[13].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[14].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[15].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[16].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[17].punkVal,
						pdispparams->rgvarg[18].lVal,
						pdispparams->rgvarg[19].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[20].lVal,
						pdispparams->rgvarg[21].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[22].lVal,
						pdispparams->rgvarg[23].lVal);
				}
			}

			break;
		}

		case DISPID_INITIALIZE_PERSONALITY_VISACOM_IO_PROVIDER:
		{
			ATLASSERT(pdispparams->cArgs == 3);
			if (pdispparams->cArgs != 3)
				return DISP_E_BADPARAMCOUNT;

#ifndef NTL_NO_VISACOM
			CComQIPtr<IVisaSession> spVisaSession = pdispparams->rgvarg[0].punkVal;
			CComQIPtr<IMessage> spMessage = pdispparams->rgvarg[1].punkVal;
			CComQIPtr<IFormattedIO488> spFormattedIO = pdispparams->rgvarg[2].punkVal;

			hr = pT->InitializePersonalityVisaComIOProvider(
					spVisaSession,
					spMessage,
					spFormattedIO);
#else
			ATLASSERT(FALSE);
			hr = E_FAIL;
#endif

			break;
		}

		case DISPID_INITIALIZE_PERSONALITY_VISA_IO_PROVIDER:
		{
			ATLASSERT(pdispparams->cArgs == 2);
			if (pdispparams->cArgs != 2)
				return DISP_E_BADPARAMCOUNT;

#ifndef NTL_NO_VISA
			hr = pT->InitializePersonalityVisaIOProvider(
					(HMODULE)pdispparams->rgvarg[0].ullVal,
					pdispparams->rgvarg[1].ulVal);
#else
			ATLASSERT(FALSE);
			hr = E_FAIL;
#endif

			break;
		}

		case DISPID_INITIALIZE_PERSONALITY_NULL_IO_PROVIDER:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;

			hr = pT->InitializePersonalityNullIOProvider();

			break;
		}

		case DISPID_INITIALIZE_PERSONALITY_CUSTOM_IO_PROVIDER:
		{
			ATLASSERT(pdispparams->cArgs == 1);
			if (pdispparams->cArgs != 1)
				return DISP_E_BADPARAMCOUNT;

			hr = pT->InitializePersonalityCustomIOProvider(
					pdispparams->rgvarg[0].lVal);

			break;
		}

		case DISPID_FINAL_INITIALIZE_PERSONALITY:
		{
			ATLASSERT(pdispparams->cArgs == 2);
			if (pdispparams->cArgs != 2)
				return DISP_E_BADPARAMCOUNT;

			hr = pT->FinalInitializePersonality(
				pdispparams->rgvarg[0].lVal,
				pdispparams->rgvarg[1].bstrVal);

			break;
		}

		// Activation methods called from personality host
		case DISPID_SELECT_PERSONALITY:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_SelectPersonality();
			break;
		}

		case DISPID_DESELECT_PERSONALITY:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_DeSelectPersonality();
			break;
		}

		// IIviDriver methods called from personality host
		case DISPID_CLOSE:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_Close();
			break;
		}

		// IIviDriverUtility methods called from personality host
		case DISPID_DISABLE:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_Disable();
			break;
		}
		case DISPID_LOCKOBJECT:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_LockObject();
			break;
		}
		case DISPID_RESET:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_Reset();
			break;
		}
		case DISPID_RESET_WITH_DEFAULTS:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_ResetWithDefaults();
			break;
		}

		// IIviDriverOperation methods called from personality host
		case DISPID_CACHE:
		{
			ATLASSERT(pdispparams->cArgs == 1);
			if (pdispparams->cArgs != 1)
				return DISP_E_BADPARAMCOUNT;
			
			VARIANTARG varArg = pdispparams->rgvarg[0];
			if (varArg.vt != VT_BOOL)
				return DISP_E_TYPEMISMATCH;

			hr = pT->_put_Cache(varArg.boolVal);
			break;
		}
		case DISPID_INTERCHANGE_CHECK:
		{
			ATLASSERT(pdispparams->cArgs == 1);
			if (pdispparams->cArgs != 1)
				return DISP_E_BADPARAMCOUNT;
			
			VARIANTARG varArg = pdispparams->rgvarg[0];
			if (varArg.vt != VT_BOOL)
				return DISP_E_TYPEMISMATCH;

			hr = pT->_put_InterchangeCheck(varArg.boolVal);
			break;
		}
		case DISPID_QUERY_INSTRUMENT_STATUS:
		{
			ATLASSERT(pdispparams->cArgs == 1);
			if (pdispparams->cArgs != 1)
				return DISP_E_BADPARAMCOUNT;
			
			VARIANTARG varArg = pdispparams->rgvarg[0];
			if (varArg.vt != VT_BOOL)
				return DISP_E_TYPEMISMATCH;

			hr = pT->_put_QueryInstrumentStatus(varArg.boolVal);
			break;
		}
		case DISPID_RECORD_COERCIONS:
		{
			ATLASSERT(pdispparams->cArgs == 1);
			if (pdispparams->cArgs != 1)
				return DISP_E_BADPARAMCOUNT;
			
			VARIANTARG varArg = pdispparams->rgvarg[0];
			if (varArg.vt != VT_BOOL)
				return DISP_E_TYPEMISMATCH;

			hr = pT->_put_RecordCoercions(varArg.boolVal);
			break;
		}
		case DISPID_RANGE_CHECK:
		{
			ATLASSERT(pdispparams->cArgs == 1);
			if (pdispparams->cArgs != 1)
				return DISP_E_BADPARAMCOUNT;
			
			VARIANTARG varArg = pdispparams->rgvarg[0];
			if (varArg.vt != VT_BOOL)
				return DISP_E_TYPEMISMATCH;

			hr = pT->_put_RangeCheck(varArg.boolVal);
			break;
		}
		case DISPID_SIMULATE:
		{
			ATLASSERT(pdispparams->cArgs == 1);
			if (pdispparams->cArgs != 1)
				return DISP_E_BADPARAMCOUNT;
			
			VARIANTARG varArg = pdispparams->rgvarg[0];
			if (varArg.vt != VT_BOOL)
				return DISP_E_TYPEMISMATCH;

			hr = pT->_put_Simulate(varArg.boolVal);
			break;
		}
		case DISPID_INVALIDATE_ALL_ATTRIBUTES:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_InvalidateAllAttributes();
			break;
		}
		case DISPID_RESET_INTERCHANGE_CHECK:
		{
			ATLASSERT(pdispparams->cArgs == 0);
			if (pdispparams->cArgs != 0)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_ResetInterchangeCheck();
			break;
		}
		case DISPID_SET_TRACER_STATE:
		{
			ATLASSERT(pdispparams->cArgs == 7);
			if (pdispparams->cArgs != 7)
				return DISP_E_BADPARAMCOUNT;
			
			hr = pT->_SetTracerState(
						pdispparams->rgvarg[0].punkVal,
						pdispparams->rgvarg[1].lVal,
						pdispparams->rgvarg[2].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[3].lVal,
						pdispparams->rgvarg[4].boolVal != VARIANT_FALSE,
						pdispparams->rgvarg[5].lVal,
						pdispparams->rgvarg[6].lVal);
			break;
		}
		default:
		{
			hr = DISP_E_MEMBERNOTFOUND;
			break;
		}
	}

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
//
//	CPersonality
//

template <class DriverClass, class IOProviderClass>
class CPersonality :
	public CObjectModelRootNodeBase<DriverClass, IOProviderClass>,
	public IPersonalityDispatchImpl<DriverClass>
{
public:
	CPersonality();
	virtual ~CPersonality();

	virtual HRESULT InternalFinalConstruct();

	virtual CString GetVisaDllFileName();

	// Initialization methods called from personality host
	STDMETHOD(InitializePersonality)(
		IUnknown* punkHost,
		BSTR bstrHostID,
		BSTR bstrPersonalityName,
		BSTR bstrVisaDllFileName,
		IIviEventServer* pEventServer,		
		long lSourceCookie,
		long lSinkCookie,
		long lPerfObjectInstanceID,
		BSTR bstrPerfObjectInstanceName,
		BSTR bstrModel,
		IIviDriverSession* pDriverSession,
		bool bCache,
		bool bInterchangeCheck,
		bool bQueryInstrStatus,
		bool bRecordCoercions,
		bool bRangeCheck,
		bool bSimulate,
		IUnknown* punkTraceXmlDoc,
		long nTraceState,
		bool bTraceEnabled,
		long nTraceSizeMax,
		bool bTraceArray,
		long nTraceArraySizeMax,
		long nTraceSaveInterval);

#ifndef NTL_NO_VISACOM
	STDMETHOD(InitializePersonalityVisaComIOProvider)(
		IVisaSession* pVisaSession,
		IMessage* pMessage,		
		IFormattedIO488* pFormattedIO);
#endif

#ifndef NTL_NO_VISA
	STDMETHOD(InitializePersonalityVisaIOProvider)(
		HMODULE hModuleVisa,
		ViSession viSession);
#endif

	STDMETHOD(InitializePersonalityNullIOProvider)();

	STDMETHOD(InitializePersonalityCustomIOProvider)(
		long lCustomIOCookie);

	STDMETHOD(FinalInitializePersonality)(
		long lPerfObjectInstanceID,
		BSTR bstrPerfObjectInstanceName);

public:
	// CCoercionLogManager overrides
	virtual void AddCoercionRecord(const CString& strRecord);

	// Activation methods called from personality host
	STDMETHOD(_SelectPersonality)();
	STDMETHOD(_DeSelectPersonality)();

	// IIviDriver methods called from personality host
	STDMETHOD(_Close)();

	// IIviDriverUtility methods called from personality host
	STDMETHOD(_Disable)();
	STDMETHOD(_LockObject)();
	STDMETHOD(_Reset)();
	STDMETHOD(_ResetWithDefaults)();
	STDMETHOD(_UnlockObject)();

	// IIviDriverOperation methods called from personality host
	STDMETHOD(_put_Cache)(VARIANT_BOOL newVal);
	STDMETHOD(_put_InterchangeCheck)(VARIANT_BOOL newVal);
	STDMETHOD(_put_QueryInstrumentStatus)(VARIANT_BOOL newVal);
	STDMETHOD(_put_RangeCheck)(VARIANT_BOOL newVal);
	STDMETHOD(_put_RecordCoercions)(VARIANT_BOOL newVal);
	STDMETHOD(_put_Simulate)(VARIANT_BOOL newVal);
	STDMETHOD(_InvalidateAllAttributes)();
	STDMETHOD(_ResetInterchangeCheck)();

	STDMETHOD(_SetTracerState)(	
		IUnknown* punkTraceXmlDoc,
		long nTraceState,
		bool bTraceEnabled,
		long nTraceSizeMax,
		bool bTraceArray,
		long nTraceArraySizeMax,
		long nTraceSaveInterval);

protected:
	HRESULT InvokeMethodOnPersonalityHost(const CString& strMethodName);
	HRESULT InvokeMethodOnPersonalityHost(const CString& strMethodName, CComVariant varParam);
	HRESULT InvokeMethodOnPersonalityHost(const CString& strMethodName, CComVariant* varParamList, int nParams);
	HRESULT InvokePropertyOnPersonalityHost(const CString& strPropertyName, CComVariant varParam);

public:
	const CString& GetHostID() const;

	virtual bool GetActive();					// override of CObjectModelRootNodeBase::GetActive()
	virtual HRESULT ActivatePersonality();		// override of CObjectModelRootNodeBase::ActivatePersonality()
	virtual CString GetSelectCommand() = 0;		// Users must override this function to provide personality-specific select command

	virtual bool IsInstalled();					// Users may override this function to indicate if the personality is installed in the instrument
	virtual bool IsLicensed();					// Users may override this function to indicate if the personality is licensed

public:
	// CCoercionLogManager overrides
	virtual CCoercionLog* GetCoercionLog();

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

protected:
	bool m_bIsInstalled;
	bool m_bIsLicensed;
	bool m_bActive;
	IUnknown* m_punkHost;
	CString m_strHostID;
	CString m_strPersonalityName;
	CString m_strVisaDllFileName;
	CTraceUser* m_pTracer;
};

template <class DriverClass, class IOProviderClass>
CPersonality<DriverClass, IOProviderClass>::CPersonality()
{
	m_bActive = false;
	m_bIsLicensed = true;
	m_bIsInstalled = true;
	m_punkHost = NULL;
	m_strHostID = _T("");
	m_pTracer = new CTraceUser();
}

template <class DriverClass, class IOProviderClass>
CPersonality<DriverClass, IOProviderClass>::~CPersonality()
{
}

template <class DriverClass, class IOProviderClass>
HRESULT CPersonality<DriverClass, IOProviderClass>::InternalFinalConstruct()
{
	return S_OK;
}

template <class DriverClass, class IOProviderClass>
CString CPersonality<DriverClass, IOProviderClass>::GetVisaDllFileName()
{
	return m_strVisaDllFileName;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::InitializePersonality(
	IUnknown* punkHost,
	BSTR bstrHostID,
	BSTR bstrPersonalityName,
	BSTR bstrVisaDllFileName,
	IIviEventServer* pEventServer, 
	long lSourceCookie, 
	long lSinkCookie, 
	long lPerfObjectInstanceID,
	BSTR bstrPerfObjectInstanceName,
	BSTR bstrModel,
	IIviDriverSession* pDriverSession,
	bool bCache,
	bool bInterchangeCheck,
	bool bQueryInstrStatus,
	bool bRecordCoercions,
	bool bRangeCheck,
	bool bSimulate,
	IUnknown* punkTraceXmlDoc,
	long nTraceState,
	bool bTraceEnabled,
	long nTraceSizeMax,
	bool bTraceArray,
	long nTraceArraySizeMax,
	long nTraceSaveInterval)
{
	NTL_UNUSED(bstrPerfObjectInstanceName);
	NTL_UNUSED(lPerfObjectInstanceID);
	
	DriverClass* pT = static_cast<DriverClass*>(this);

	HRESULT hr = S_OK;

	(m_punkHost = punkHost)->AddRef();
	m_strHostID = COLE2T(bstrHostID);
	m_strPersonalityName = COLE2T(bstrPersonalityName);
	m_strVisaDllFileName = COLE2T(bstrVisaDllFileName);
	m_strModel = COLE2T(bstrModel);
	m_bCache = bCache;
	m_bInterchangeCheck = bInterchangeCheck;

	m_bQueryInstrStatus = bQueryInstrStatus;
	// Keep the I/O in sync with this va0lue

	m_bRecordCoercions = bRecordCoercions;
	m_bRangeCheck = bRangeCheck;
	m_bSimulate = bSimulate;
	
	m_pTracer->SetTraceDocument(punkTraceXmlDoc);
	m_pTracer->SetTraceState((TraceState)nTraceState);
	m_pTracer->SetTraceEnabled(bTraceEnabled);
	m_pTracer->SetTraceSizeMax(nTraceSizeMax);
	m_pTracer->SetTraceArray(bTraceArray);
	m_pTracer->SetTraceArraySizeMax(nTraceArraySizeMax);
	m_pTracer->SetTraceSaveInterval(nTraceSaveInterval);

	if (pDriverSession != NULL)
	{
		hr = pT->BuildVirtualNameMaps(pDriverSession);
	}

	if (SUCCEEDED(hr))
	{
		hr = InitializeEventServerManager(pEventServer, lSourceCookie, lSinkCookie);
	}

	return hr;
}

#ifndef NTL_NO_VISACOM
template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::InitializePersonalityVisaComIOProvider(
		IVisaSession* pVisaSession,
		IMessage* pMessage,		
		IFormattedIO488* pFormattedIO)	 
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CVisaComIOProvider* pProvider = dynamic_cast<CVisaComIOProvider*>(this);

	hr = pProvider->ioprvInitializeIOProvider(pT, pT, pT, pVisaSession, pMessage, pFormattedIO);

	return hr;
}
#endif

#ifndef NTL_NO_VISA
template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::InitializePersonalityVisaIOProvider(
		HMODULE hModuleVisa,
		ViSession viSession)	
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CVisaIOProvider* pProvider = dynamic_cast<CVisaIOProvider*>(this);

	hr = pProvider->ioprvInitializeIOProvider(pT, pT, pT, viSession, hModuleVisa);

	return hr;
}
#endif

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::InitializePersonalityNullIOProvider()
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CNullIOProvider* pProvider = dynamic_cast<CNullIOProvider*>(this);

	hr = pProvider->ioprvInitializeIOProvider(pT, pT, pT, CComBSTR(_T("")));

	return hr;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::InitializePersonalityCustomIOProvider(
		long lCustomIOCookie)
{
	HRESULT hr = S_OK;

	CCustomIOProvider* pProvider = dynamic_cast<CCustomIOProvider*>(this);
	hr = pProvider->ioprvInitializeIOProvider(lCustomIOCookie);

	return hr;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::FinalInitializePersonality(
	long lPerfObjectInstanceID,
	BSTR bstrPerfObjectInstanceName)
{	
	DriverClass* pT = static_cast<DriverClass*>(this);
	CComObject< CObjectModelRootNode<DriverClass> >* pNode = static_cast<CComObject< CObjectModelRootNode<DriverClass> >*>(this);

	HRESULT hr = S_OK;

	pT->m_bInitialized = true;

	// Call to CObjectModelNode::FinalInitialize, NOT the DriverClass::FinalInitialize
	hr = pNode->FinalInitialize(lPerfObjectInstanceID, bstrPerfObjectInstanceName);

	m_bIsInstalled = IsInstalled();
	m_bIsLicensed = IsLicensed();

	return hr;
}

// CCoercionLogManager overrides
template <class DriverClass, class IOProviderClass>
void CPersonality<DriverClass, IOProviderClass>::AddCoercionRecord(const CString& strRecord)
{
	CComVariant varRecord = LPCTSTR(strRecord);
	InvokeMethodOnPersonalityHost("AddCoercionRecord", varRecord);
}

// Activation methods called from personality host
template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_SelectPersonality()
{
	if (!m_bIsInstalled)
		return ReportError(GetDriverErrorResourceId(NTL_IDS_PERSONALITY_NOT_INSTALLED));

	if (!m_bIsLicensed)
		return ReportError(GetDriverErrorResourceId(NTL_IDS_PERSONALITY_NOT_LICENSED));

	HRESULT hr = S_OK;

	CString strCommand = GetSelectCommand();
	strCommand.Trim();
	if (strCommand == _T("") || GetSimulate())
	{
		m_bActive = true;
	}
	else
	{
		hr = InstrPrintf(strCommand);
		if (SUCCEEDED(hr))
		{
			m_bActive = true;
		}
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_DeSelectPersonality()
{
	m_bActive = false;

	return S_OK;
}

// IIviDriver methods called from personality host
template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_Close()
{
	DriverClass* pT = static_cast<DriverClass*>(this);

	if (!GetInitialized())
		return pT->ReportError(IDS_E_IVI_NOT_INITIALIZED);

	HRESULT hr = S_OK;

	CloseIOManager();

	// It's important to delete all cache entries when closing, else there
	// will be an error if we try and re-initialize the same driver instance.
	pT->DestroyAllCacheEntries();

	m_bInitialized = false;
	m_bActive = false;

	hr = pT->FinalClose();

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

	return hr;
}

// IIviDriverUtility methods called from personality host
template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_Disable()
{
	return S_OK;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_LockObject()
{
	return E_NOTIMPL;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_Reset()
{
	InternalResetObjectState();

	InvalidateCacheAll();

	return S_OK;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_ResetWithDefaults()
{
	HRESULT hr = S_OK;

	// NOTE: The member variables for the various options are reset to their original values by calls
	// coming in from the personality host.
	hr = _Reset();

	return hr;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_UnlockObject()
{
	return E_NOTIMPL;
}

// IIviDriverOperation methods called from personality host
template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_put_Cache(VARIANT_BOOL newVal)
{
	m_bCache = (newVal != VARIANT_FALSE);

	if (newVal == VARIANT_FALSE)
	{
		_InvalidateAllAttributes();
	}

	return S_OK;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_put_InterchangeCheck(VARIANT_BOOL newVal)
{
	m_bInterchangeCheck = (newVal != VARIANT_FALSE);

	return S_OK;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_put_QueryInstrumentStatus(VARIANT_BOOL newVal)
{
	m_bQueryInstrStatus = (newVal != VARIANT_FALSE);

	return S_OK;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_put_RangeCheck(VARIANT_BOOL newVal)
{
	m_bRangeCheck = (newVal != VARIANT_FALSE);

	return S_OK;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_put_RecordCoercions(VARIANT_BOOL newVal)
{
	m_bRecordCoercions = (newVal != VARIANT_FALSE);

	return S_OK;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_put_Simulate(VARIANT_BOOL newVal)
{
	HRESULT hr = S_OK;

	m_bSimulate = (newVal != VARIANT_FALSE);

	return hr;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_SetTracerState(	
	IUnknown* punkTraceXmlDoc,
	long nTraceState,
	bool bTraceEnabled,
	long nTraceSizeMax,
	bool bTraceArray,
	long nTraceArraySizeMax,
	long nTraceSaveInterval)
{
	HRESULT hr = S_OK;

	m_pTracer->SetTraceDocument(punkTraceXmlDoc);
	m_pTracer->SetTraceState((TraceState)nTraceState);
	m_pTracer->SetTraceEnabled(bTraceEnabled);
	m_pTracer->SetTraceSizeMax(nTraceSizeMax);
	m_pTracer->SetTraceArray(bTraceArray);
	m_pTracer->SetTraceArraySizeMax(nTraceArraySizeMax);
	m_pTracer->SetTraceSaveInterval(nTraceSaveInterval);

	return hr;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_InvalidateAllAttributes()
{
	HRESULT hr = S_OK;

	InvalidateCacheAll();

	return hr;
}

template <class DriverClass, class IOProviderClass>
STDMETHODIMP CPersonality<DriverClass, IOProviderClass>::_ResetInterchangeCheck()
{
	DriverClass* pT = static_cast<DriverClass*>(this);

	return pT->ReportError(IDS_E_IVI_METHOD_NOT_SUPPORTED, _T("ResetInterchangeCheck"));
}

template <class DriverClass, class IOProviderClass>
bool CPersonality<DriverClass, IOProviderClass>::GetActive()
{
	return m_bActive;
}

template <class DriverClass, class IOProviderClass>
HRESULT CPersonality<DriverClass, IOProviderClass>::ActivatePersonality()
{
	CComVariant varName = LPCTSTR(m_strPersonalityName);
	HRESULT hr = InvokeMethodOnPersonalityHost("ActivatePersonality", varName);
	return hr;
}

template <class DriverClass, class IOProviderClass>
bool CPersonality<DriverClass, IOProviderClass>::IsInstalled()
{
	return true;
}

template <class DriverClass, class IOProviderClass>
bool CPersonality<DriverClass, IOProviderClass>::IsLicensed()
{
	return true;
}

template <class DriverClass, class IOProviderClass>
CCoercionLog* CPersonality<DriverClass, IOProviderClass>::GetCoercionLog()
{
	ATLASSERT(!"CPersonality::GetCoercionLog() should never be called.");
	return NULL;
}

template <class DriverClass, class IOProviderClass>
HRESULT CPersonality<DriverClass, IOProviderClass>::InvokeMethodOnPersonalityHost(const CString& strMethodName)
{
	HRESULT hr = E_POINTER;

	ATLASSERT(m_punkHost != NULL);
	if (m_punkHost != NULL)
	{
		CComDispatchDriver dispatchDriver(m_punkHost);
		hr = dispatchDriver.Invoke0(CT2OLE(strMethodName));
		ATLASSERT(SUCCEEDED(hr));
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
HRESULT CPersonality<DriverClass, IOProviderClass>::InvokeMethodOnPersonalityHost(const CString& strMethodName, CComVariant varParam)
{
	HRESULT hr = E_POINTER;

	ATLASSERT(m_punkHost != NULL);
	if (m_punkHost != NULL)
	{
		CComDispatchDriver dispatchDriver(m_punkHost);
		hr = dispatchDriver.Invoke1(CT2OLE(strMethodName), &varParam);
		ATLASSERT(SUCCEEDED(hr));
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
HRESULT CPersonality<DriverClass, IOProviderClass>::InvokeMethodOnPersonalityHost(const CString& strMethodName, CComVariant* varParamList, int nParams)
{
	HRESULT hr = E_POINTER;

	ATLASSERT(m_punkHost != NULL);
	if (m_punkHost != NULL)
	{
		CComDispatchDriver dispatchDriver(punkHost);
		hr = dispatchDriver.InvokeN(CT2OLE(strMethodName), &varParamList);
		ATLASSERT(SUCCEEDED(hr));
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
HRESULT CPersonality<DriverClass, IOProviderClass>::InvokePropertyOnPersonalityHost(const CString& strPropertyName, CComVariant varParam)
{
	HRESULT hr = E_POINTER;

	ATLASSERT(m_punkHost != NULL);
	if (m_punkHost != NULL)
	{
		CComDispatchDriver dispatchDriver(punkHost);
		hr = dispatchDriver.PutPropertyByName(CT2OLE(strPropertyName), &varParam);
		ATLASSERT(SUCCEEDED(hr));
	}

	return hr;
}

template <class DriverClass, class IOProviderClass>
const CString& CPersonality<DriverClass, IOProviderClass>::GetHostID() const
{
	return m_strHostID;
}

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

template <class DriverClass, class IOProviderClass>
MSXML2::IXMLDOMElementPtr CPersonality<DriverClass, IOProviderClass>::GetCurrentTraceElement()
{
	HRESULT hr = S_OK;

	MSXML2::IXMLDOMElementPtr spCurrentElement;
	IUnknown* punkCurrentElement = NULL;
	CComVariant varCurrentElement;
	varCurrentElement.vt = VT_BYREF | VT_UNKNOWN;
	varCurrentElement.ppunkVal = &punkCurrentElement;
	hr = InvokeMethodOnPersonalityHost("GetCurrentTraceElement", varCurrentElement);
	ATLASSERT(SUCCEEDED(hr));
	if (SUCCEEDED(hr) && (punkCurrentElement != NULL))
	{
		spCurrentElement = punkCurrentElement;
	}

	return spCurrentElement;
}

template <class DriverClass, class IOProviderClass>
void CPersonality<DriverClass, IOProviderClass>::SetCurrentTraceElement(MSXML2::IXMLDOMElementPtr spCurrentElement)
{
	HRESULT hr = S_OK;

	hr = InvokeMethodOnPersonalityHost("SetCurrentTraceElement", (IUnknown*)spCurrentElement);
	ATLASSERT(SUCCEEDED(hr));
}

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

	hr = InvokeMethodOnPersonalityHost("CommitTraceData");
	ATLASSERT(SUCCEEDED(hr));

	return hr;
}

#endif // __NTLPERSONALITY_INCLUDED
