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

#ifndef __NTLIO_INCLUDED
#define __NTLIO_INCLUDED

#include <stdarg.h>
#include <atlrx.h>
#include "ntlutil.h"
#include "ntlioprovider.h"
#include "ntlioprovidernull.h"
#include "ntlioprovidercustom.h"
#include <stack>
using namespace std;

#ifndef NTL_NO_VISA
#include "ntlioprovidervisa.h"
#endif

#ifndef NTL_NO_VISACOM
#include "ntlioprovidervisacom.h"
#endif


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

#define MAX_ENUM_STRING			1024
#define MAX_BOOL_STRING			1024
#define DEFAULT_STRING_LENGTH	1024


///////////////////////////////////////////////////////////////////////////////
//	Boolean commands

const CString& GetBooleanTrueCommand();		// Implemented in generated code
const CString& GetBooleanFalseCommand();	// Implemented in generated code

///////////////////////////////////////////////////////////////////////////////
//	CInstrumentCommandManager

class CInstrumentCommandManager
{
public:
	CString GetInstrCommand()
	{
		if (!m_stackCommands.empty())
			return LPCTSTR(CA2T(m_stackCommands.top().c_str()));
		else
			return _T("");
	}
	
	void PushInstrCommand(const CString& strCmd)
	{
		string sCmd = CT2A(strCmd);
		m_stackCommands.push(sCmd);
	}
	
	CString PopInstrCommand()
	{
		CString strCmd = CA2T(m_stackCommands.top().c_str());
		m_stackCommands.pop();

		return strCmd;
	}

	CString FormatInstrCommand(CString strCommand, ...)
	{
		// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT  BSTR or LPWSTR
		va_list argPtr;
		va_start(argPtr, strCommand);

		CString strResult;
		strResult.FormatV(strCommand, argPtr);

		va_end(argPtr);

		return strResult;
	}

private:
	stack<string> m_stackCommands;
};


///////////////////////////////////////////////////////////////////////////////
//	CDriverIOManager

template <class DriverClass, class RootClass>
class CDriverIOManager :
	public CInstrumentCommandManager
{
public:
	CDriverIOManager();
	virtual ~CDriverIOManager();

	///////////////////////////////////////////////////////////////////////////////
	// Initialization

	HRESULT InitializeIOManager(BSTR bstrResourceDescriptor);
	HRESULT CloseIOManager();
	HRESULT SetTrailingForReads(const CString& strTrailing);
	HRESULT SetTrailingForWrites(const CString& strTrailing);

	///////////////////////////////////////////////////////////////////////////////
	// Error checking

	virtual HRESULT PollInstrumentErrors();
	virtual HRESULT DeviceClear();
	virtual HRESULT ReadSTB(long* plStatus);

	///////////////////////////////////////////////////////////////////////////////
	// Timeout

	virtual HRESULT SetIOTimeout(long lTimeout);
	virtual HRESULT GetIOTimeout(long* plTimeout);
	virtual HRESULT IsTimeout(bool* pbTimeout);

	///////////////////////////////////////////////////////////////////////////////
	// Wrappers around the IMessage interface
#ifndef NTL_MANAGED_CPP_EXTENSIONS
	virtual HRESULT InstrPrintf(LPCTSTR pszFormat, ...);
	virtual HRESULT InstrPrintfNoPoll(LPCTSTR pszFormat, ...);
#endif // NTL_MANAGED_CPP_EXTENSIONS	
	virtual HRESULT InstrQuery(const CString& strCommand, double* pdResult, long lTimeout = -2);
	virtual HRESULT InstrQuery(const CString& strCommand, float* pfResult, long lTimeout = -2);
	virtual HRESULT InstrQuery(const CString& strCommand, long* plResult, long lTimeout = -2);
	virtual HRESULT InstrQuery(const CString& strCommand, short* psResult, long lTimeout = -2);
	virtual HRESULT InstrQuery(const CString& strCommand, BYTE* pbResult, long lTimeout = -2);
	virtual HRESULT InstrQuery(const CString& strCommand, CString& strResult, long cchDesired, long lTimeout = -2);
#ifndef NTL_MANAGED_CPP_EXTENSIONS	
	virtual HRESULT InstrQueryf(LPCTSTR pszFormat, double* pdResult, ...);
	virtual HRESULT InstrQueryf(LPCTSTR pszFormat, float* pfResult, ...);
	virtual HRESULT InstrQueryf(LPCTSTR pszFormat, long* plResult, ...);
	virtual HRESULT InstrQueryf(LPCTSTR pszFormat, short* psResult, ...);
	virtual HRESULT InstrQueryf(LPCTSTR pszFormat, BYTE* pbResult, ...);
	virtual HRESULT InstrQueryf(LPCTSTR pszFormat, CString& strResult, long cchDesired, ...);
#endif // NTL_MANAGED_CPP_EXTENSIONS	
	virtual HRESULT InstrRead(BYTE* pBuf, long cbDesired, long* plActualLength, long lTimeout = -2);
	virtual HRESULT InstrRead(CString& strResult, long cbDesired, long lTimeout = -2, bool bRemoveTrailing = true);
	virtual HRESULT InstrRead(SAFEARRAY** ppsa, long cbDesired = -1, long lTimeout = -2);

	virtual HRESULT InstrWrite(BYTE* pBuf, long cbDesired, long* pcbActual, long lTimeout = -2);
	virtual HRESULT InstrWrite(const CString& strCommand, long lTimeout = -2);
	virtual HRESULT InstrWrite(SAFEARRAY* psa, long cbDesired = -1, long lTimeout = -2);

	virtual HRESULT InstrWriteNoPoll(BYTE* pBuf, long cbDesired, long* pcbActual, long lTimeout = -2);
	virtual HRESULT InstrWriteNoPoll(const CString& strCommand, long lTimeout = -2);
	virtual HRESULT InstrWriteNoPoll(SAFEARRAY* psa, long cbDesired = -1, long lTimeout = -2);

	///////////////////////////////////////////////////////////////////////////////
	// Wrappers around the IFormattedIO488 interface

	virtual HRESULT FormattedWriteString(const CString& strData, bool bFlushAndEnd = true, long lTimeout = -2);

	virtual HRESULT FormattedWriteNumber(double val, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteNumber(long val, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteNumber(BYTE val, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteNumber(VARIANT data, NtlAsciiType type, bool bFlushAndEnd = true, long lTimeout = -2);

	virtual HRESULT FormattedWriteList(double* pValues, long lLength, const CString& strListSeparator, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteList(long* pValues, long lLength, const CString& strListSeparator, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteList(BYTE* pValues, long lLength, const CString& strListSeparator, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteList(SAFEARRAY* psa, NtlAsciiType type, const CString& strListSeparator, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteList(VARIANT data, NtlAsciiType type, const CString& strListSeparator, bool bFlushAndEnd = true, long lTimeout = -2);

	virtual HRESULT FormattedWriteIEEEBlock(const CString& strCommand, double* pValues, long lLength, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteIEEEBlock(const CString& strCommand, long* pValues, long lLength, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteIEEEBlock(const CString& strCommand, short* pValues, long lLength, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteIEEEBlock(const CString& strCommand, BYTE* pValues, long lLength, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteIEEEBlock(const CString& strCommand, VARIANT data, bool bFlushAndEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedWriteIEEEBlock(const CString& strCommand, SAFEARRAY* pData, bool bFlushAndEnd = true, long lTimeout = -2);

	virtual HRESULT FormattedReadString(CString& strResult, long lTimeout = -2);
	virtual HRESULT FormattedReadString(BSTR* pbstrResult, long lTimeout = -2);

	virtual HRESULT FormattedReadNumber(double* pValue, bool bFlushToEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedReadNumber(long* pValue, bool bFlushToEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedReadNumber(BYTE* pValue, bool bFlushToEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedReadNumber(NtlAsciiType type, VARIANT* pData, bool bFlushToEnd = true, long lTimeout = -2);

	virtual HRESULT FormattedReadList(double* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout = -2);
	virtual HRESULT FormattedReadList(long* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout = -2);
	virtual HRESULT FormattedReadList(BYTE* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout = -2);
	virtual HRESULT FormattedReadList(CComBSTR* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout = -2);
	virtual HRESULT FormattedReadList(NtlAsciiType type, const CString& strListSeparator, VARIANT* pData, long lTimeout = -2);
	virtual HRESULT FormattedReadList(NtlAsciiType type, const CString& strListSeparator, SAFEARRAY** pData, long lTimeout = -2);

	virtual HRESULT FormattedReadIEEEBlock(double* pValues, long lMaxLength, long* plActualLength, bool bSeekToBlock = false, bool bFlushToEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedReadIEEEBlock(long* pValues, long lMaxLength, long* plActualLength, bool bSeekToBlock = false, bool bFlushToEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedReadIEEEBlock(BYTE* pValues, long lMaxLength, long* plActualLength, bool bSeekToBlock = false, bool bFlushToEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedReadIEEEBlock(NtlBinaryType type, VARIANT* pData, bool bSeekToBlock = false, bool bFlushToEnd = true, long lTimeout = -2);
	virtual HRESULT FormattedReadIEEEBlock(NtlBinaryType type, SAFEARRAY** pData, bool bSeekToBlock = false, bool bFlushToEnd = true, long lTimeout = -2);

	virtual HRESULT FormattedFlushWrite(bool bSendEND = true, long lTimeout = -2);
	virtual HRESULT FormattedFlushRead(long lTimeout = -2);
	virtual HRESULT FormattedSetBufferSize(NtlBufferMask mask, long lSize);

	///////////////////////////////////////////////////////////////////////////////
	// Wrappers around the IRegister interface

	virtual HRESULT RegisterIn8(UINT16 space, UINT32 offset, UINT8* val);
	virtual HRESULT RegisterOut8(UINT16 space, UINT32 offset, UINT8 val);
	virtual HRESULT RegisterIn16(UINT16 space, UINT32 offset, UINT16* val);
	virtual HRESULT RegisterOut16(UINT16 space, UINT32 offset, UINT16 val);
	virtual HRESULT RegisterIn32(UINT16 space, UINT32 offset, UINT32* val);
	virtual HRESULT RegisterOut32(UINT16 space, UINT32 offset, UINT32 val);

	virtual HRESULT RegisterMoveIn8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[]);
	virtual HRESULT RegisterMoveOut8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[]);
	virtual HRESULT RegisterMoveIn16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[]);
	virtual HRESULT RegisterMoveOut16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[]);
	virtual HRESULT RegisterMoveIn32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[]);
	virtual HRESULT RegisterMoveOut32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[]);

	///////////////////////////////////////////////////////////////////////////////
	// High level functions for pre-built commands

	virtual HRESULT InstrPrintCommand();
	virtual HRESULT InstrPrintCommandNoPoll();

	virtual HRESULT InstrQueryCommand(double* pdResult, long lTimeout = -2);
	virtual HRESULT InstrQueryCommand(float* pfResult, long lTimeout = -2);
	virtual HRESULT InstrQueryCommand(long* plResult, long lTimeout = -2);
	virtual HRESULT InstrQueryCommand(short* psResult, long lTimeout = -2);
	virtual HRESULT InstrQueryCommand(BYTE* pbResult, long lTimeout = -2);
	virtual HRESULT InstrQueryCommand(CString& strResult, long cchDesired, long lTimeout = -2);
	virtual HRESULT InstrQueryCommand(BSTR* pbstrResult, long lTimeout = -2);
	virtual HRESULT InstrQueryCommandBool(VARIANT_BOOL* plResult, long lTimeout = -2);


	template <typename EnumType>
	HRESULT InstrQueryCommandEnum(EnumType* peResult, long lTimeout = -2)
	{
		if (peResult == NULL)
			return E_POINTER;

		HRESULT hr = S_OK;

		DriverClass* pT = static_cast<DriverClass*>(this);
		CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryCommandEnum"), IN_PARAM(lTimeout), OUT_PARAM(peResult), NULL);

		CString strEnumString;
		hr = InstrQueryCommand(strEnumString, MAX_ENUM_STRING, lTimeout);
		if (SUCCEEDED(hr))
		{
			bool bFound = pT->EnumFromString<EnumType>(strEnumString, *peResult);
			if (!bFound)
			{
				hr = pT->ReportError(IDS_E_IVI_UNEXPECTED_RESPONSE);
			}
		}

		return hr;
	}

protected:
	virtual CString GetVisaDllFileName() = 0;
};


template <class DriverClass, class RootClass>
CDriverIOManager<DriverClass, RootClass>::CDriverIOManager()
{
}

template <class DriverClass, class RootClass>
CDriverIOManager<DriverClass, RootClass>::~CDriverIOManager()
{
}

///////////////////////////////////////////////////////////////////////////////
// Initialization

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InitializeIOManager(BSTR bstrResourceDescriptor)
{
	HRESULT hr = S_OK;

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

	hr = pT->ioprvInitializeIOProvider(pT, pT, pT, bstrResourceDescriptor);
	if (hr == E_IVI_RESOURCE_UNKNOWN)
	{
		hr = pT->ReportError(IDS_E_IVI_RESOURCE_UNKNOWN);
	}

	return hr;
}
template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::CloseIOManager()
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	hr = pT->ioprvCloseIOProvider();

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::SetTrailingForReads(const CString& strTrailing)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, "CDriverIOManager", "SetTrailingForReads", IN_CSTRING_PARAM(strTrailing), NULL);

	hr = pT->GetRoot()->ioprvSetTrailingForReads(strTrailing);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::SetTrailingForWrites(const CString& strTrailing)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, "CDriverIOManager", "SetTrailingForWrites", IN_CSTRING_PARAM(strTrailing), NULL);

	hr = pT->GetRoot()->ioprvSetTrailingForWrites(strTrailing);

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// Error checking

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::PollInstrumentErrors()
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("PollInstrumentErrors"), NULL);

	hr = pT->GetRoot()->ioprvPollInstrumentErrors();

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::DeviceClear()
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("DeviceClear"), NULL);

	hr = pT->GetRoot()->ioprvDeviceClear();

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::ReadSTB(long* plStatus)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("ReadSTB"), NULL);

	hr = pT->GetRoot()->ioprvReadSTB(plStatus);

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// Timeout

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::SetIOTimeout(long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("SetIOTimeout"), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvSetIOTimeout(lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::GetIOTimeout(long* plTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("GetIOTimeout"), OUT_PARAM(plTimeout), NULL);

	hr = pT->GetRoot()->ioprvGetIOTimeout(plTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::IsTimeout(bool* pbTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("IsTimeout"), OUT_PARAM(pbTimeout), NULL);

	hr = pT->GetRoot()->ioprvIsTimeout(pbTimeout);

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// Wrappers around the IMessage interface
#ifndef NTL_MANAGED_CPP_EXTENSIONS
template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrPrintf(LPCTSTR pszFormat, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, pszFormat);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrPrintf"), IN_CSTRING_PARAM(strCmd), NULL);

	hr = pT->GetRoot()->ioprvInstrWrite(strCmd);

	va_end(argPtr);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrPrintfNoPoll(LPCTSTR pszFormat, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, pszFormat);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrPrintfNoPoll"), IN_CSTRING_PARAM(strCmd), NULL);

	hr = pT->GetRoot()->ioprvInstrWriteNoPoll(strCmd);

	va_end(argPtr);

	return hr;
}
#endif // NTL_MANAGED_CPP_EXTENSIONS
template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQuery(const CString& strCommand, double* pdResult, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQuery"), IN_CSTRING_PARAM(strCommand), OUT_PARAM(pdResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCommand, pdResult, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQuery(const CString& strCommand, float* pfResult, long lTimeout)
{
	HRESULT hr = S_OK;

	double dResult = 0;
	hr = InstrQuery(strCommand, &dResult, lTimeout);
	*pfResult = (float)dResult;

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQuery(const CString& strCommand, long* plResult, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQuery"), IN_CSTRING_PARAM(strCommand), OUT_PARAM(plResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCommand, plResult, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQuery(const CString& strCommand, short* psResult, long lTimeout)
{
	HRESULT hr = S_OK;

	long lResult = 0;
	hr = InstrQuery(strCommand, &lResult, lTimeout);
	*psResult = (short)lResult;

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQuery(const CString& strCommand, BYTE* pbResult, long lTimeout)
{
	HRESULT hr = S_OK;

	long lResult = 0;
	hr = InstrQuery(strCommand, &lResult, lTimeout);
	*pbResult = (BYTE)lResult;

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQuery(const CString& strCommand, CString& strResult, long cchDesired, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CComBSTR bstrResult;
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrPrintf"), IN_CSTRING_PARAM(strCommand), IN_PARAM(cchDesired), OUT_PARAM(&bstrResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCommand, strResult, cchDesired, lTimeout);

	bstrResult = CT2OLE(strResult);

	return hr;
}
#ifndef NTL_MANAGED_CPP_EXTENSIONS
template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryf(LPCTSTR pszFormat, double* pdResult, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, pdResult);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryf"), IN_CSTRING_PARAM(strCmd), OUT_PARAM(pdResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCmd, pdResult);

	va_end(argPtr);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryf(LPCTSTR pszFormat, float* pfResult, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, pfResult);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryf"), IN_CSTRING_PARAM(strCmd), OUT_PARAM(pfResult), NULL);

	double dResult = 0;
	hr = pT->GetRoot()->ioprvInstrQuery(strCmd, &dResult);
	*pfResult = (float)dResult;

	va_end(argPtr);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryf(LPCTSTR pszFormat, long* plResult, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, plResult);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryf"), IN_CSTRING_PARAM(strCmd), OUT_PARAM(plResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCmd, plResult);

	va_end(argPtr);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryf(LPCTSTR pszFormat, short* psResult, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, psResult);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryf"), IN_CSTRING_PARAM(strCmd), OUT_PARAM(psResult), NULL);

	long lResult = 0;
	hr = pT->GetRoot()->ioprvInstrQuery(strCmd, &lResult);
	*psResult = (short)lResult;

	va_end(argPtr);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryf(LPCTSTR pszFormat, BYTE* pbResult, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, pbResult);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryf"), IN_CSTRING_PARAM(strCmd), OUT_PARAM(pbResult), NULL);

	long lResult = 0;
	hr = pT->GetRoot()->ioprvInstrQuery(strCmd, &lResult);
	*pbResult = (BYTE)lResult;

	va_end(argPtr);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryf(LPCTSTR pszFormat, CString& strResult, long cchDesired, ...)
{
	HRESULT hr = S_OK;

	// IMPORTANT: Strings in the variable argument list must be LPCTSTR or CString, NOT as BSTR or LPWSTR
	va_list argPtr;
	va_start(argPtr, cchDesired);

	CString strCmd;
	strCmd.FormatV(pszFormat, argPtr);

	DriverClass* pT = static_cast<DriverClass*>(this);
	CComBSTR bstrResult;
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrPrintf"), IN_CSTRING_PARAM(strCmd), IN_PARAM(cchDesired), OUT_PARAM(&bstrResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCmd, strResult, cchDesired);

	bstrResult = CT2OLE(strResult);

	va_end(argPtr);

	return hr;
}
#endif // NTL_MANAGED_CPP_EXTENSIONS
template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrRead(BYTE* pBuf, long cbDesired, long* plActualLength, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrRead"), IN_PARAM(cbDesired), OUT_PARAM(plActualLength), IN_PARAM(lTimeout), OUT_PARAM(pBuf), NULL);

	hr = pT->GetRoot()->ioprvInstrRead(pBuf, cbDesired, plActualLength, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrRead(CString& strResult, long cchDesired, long lTimeout, bool bRemoveTrailing)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CComBSTR bstrResult;
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrRead"), IN_PARAM(cchDesired), IN_PARAM(lTimeout), IN_PARAM(bRemoveTrailing), OUT_PARAM(&bstrResult), NULL);

	hr = pT->GetRoot()->ioprvInstrRead(strResult, cchDesired, lTimeout, bRemoveTrailing);

	bstrResult = CT2OLE(strResult);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrRead(SAFEARRAY** ppsa, long cbDesired, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrRead"), IN_PARAM(cbDesired), IN_PARAM(lTimeout), OUT_PARAM(ppsa), NULL);

	hr = pT->GetRoot()->ioprvInstrRead(ppsa, cbDesired, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrWrite(BYTE* pBuf, long cbDesired, long* pcbActual, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrWrite"), IN_PARAM(cbDesired), IN_PARAM(lTimeout), OUT_PARAM(pcbActual), OUT_PARAM(pBuf), NULL);

	hr = pT->GetRoot()->ioprvInstrWrite(pBuf, cbDesired, pcbActual, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrWrite(const CString& strCommand, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrWrite"), IN_CSTRING_PARAM(strCommand), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvInstrWrite(strCommand, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrWrite(SAFEARRAY* psa, long cbDesired, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrWrite"), IN_PARAM(psa), IN_PARAM(cbDesired), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvInstrWrite(psa, cbDesired, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrWriteNoPoll(BYTE* pBuf, long cbDesired, long* pcbActual, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrWriteNoPoll"), SIZED_IN_PARAM(pBuf, cbDesired), IN_PARAM(cbDesired), IN_PARAM(lTimeout), OUT_PARAM(pcbActual), NULL);

	hr = pT->GetRoot()->ioprvInstrWriteNoPoll(pBuf, cbDesired, pcbActual, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrWriteNoPoll(const CString& strCommand, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrWriteNoPoll"), IN_CSTRING_PARAM(strCommand), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvInstrWriteNoPoll(strCommand, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrWriteNoPoll(SAFEARRAY* psa, long cbDesired, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrWriteNoPoll"), IN_PARAM(psa), IN_PARAM(cbDesired), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvInstrWriteNoPoll(psa, cbDesired, lTimeout);

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// Wrappers around the IFormattedIO488 interface

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteString(const CString& strData, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteString"), IN_CSTRING_PARAM(strData), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteString(strData, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteNumber(double val, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteNumber"), IN_PARAM(val), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteNumber(val, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteNumber(long val, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteNumber"), IN_PARAM(val), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteNumber(val, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteNumber(BYTE val, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteNumber"), IN_PARAM(val), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteNumber(val, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteNumber(VARIANT data, NtlAsciiType type, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteNumber"), IN_PARAM(data), IN_PARAM(type), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteNumber(data, type, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteList(double* pValues, long lLength, const CString& strListSeparator, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteList"), SIZED_IN_PARAM(pValues, lLength), IN_PARAM(lLength), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteList(pValues, lLength, strListSeparator, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteList(long* pValues, long lLength, const CString& strListSeparator, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteList"), SIZED_IN_PARAM(pValues, lLength), IN_PARAM(lLength), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteList(pValues, lLength, strListSeparator, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteList(BYTE* pValues, long lLength, const CString& strListSeparator, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteList"), SIZED_IN_PARAM(pValues, lLength), IN_PARAM(lLength), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteList(pValues, lLength, strListSeparator, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteList(SAFEARRAY* psa, NtlAsciiType type, const CString& strListSeparator, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteList"), IN_PARAM(psa), IN_PARAM(type), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteList(psa, type, strListSeparator, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteList(VARIANT data, NtlAsciiType type, const CString& strListSeparator, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteList"), IN_PARAM(data), IN_PARAM(type), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteList(data, type, strListSeparator, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteIEEEBlock(const CString& strCommand, double* pValues, long lLength, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteIEEEBlock"), IN_CSTRING_PARAM(strCommand), SIZED_IN_PARAM(pValues, lLength), IN_PARAM(lLength), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteIEEEBlock(strCommand, pValues, lLength, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteIEEEBlock(const CString& strCommand, long* pValues, long lLength, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteIEEEBlock"), IN_CSTRING_PARAM(strCommand), SIZED_IN_PARAM(pValues, lLength), IN_PARAM(lLength), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteIEEEBlock(strCommand, pValues, lLength, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteIEEEBlock(const CString& strCommand, short* pValues, long lLength, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteIEEEBlock"), IN_CSTRING_PARAM(strCommand), SIZED_IN_PARAM(pValues, lLength), IN_PARAM(lLength), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteIEEEBlock(strCommand, pValues, lLength, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteIEEEBlock(const CString& strCommand, BYTE* pValues, long lLength, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteIEEEBlock"), IN_CSTRING_PARAM(strCommand), SIZED_IN_PARAM(pValues, lLength), IN_PARAM(lLength), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteIEEEBlock(strCommand, pValues, lLength, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteIEEEBlock(const CString& strCommand, VARIANT data, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteIEEEBlock"), IN_CSTRING_PARAM(strCommand), IN_PARAM(data), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteIEEEBlock(strCommand, data, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedWriteIEEEBlock(const CString& strCommand, SAFEARRAY* pData, bool bFlushAndEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedWriteIEEEBlock"), IN_CSTRING_PARAM(strCommand), IN_PARAM(pData), IN_PARAM(bFlushAndEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedWriteIEEEBlock(strCommand, pData, bFlushAndEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadString(CString& strResult, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CComBSTR bstrResult;
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadString"), IN_PARAM(lTimeout), OUT_PARAM(&bstrResult), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadString(strResult, lTimeout);

	bstrResult = CT2OLE(strResult);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadString(BSTR* pbstrResult, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadString"), IN_PARAM(lTimeout), OUT_PARAM(pbstrResult), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadString(pbstrResult, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadNumber(double* pValue, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadNumber"), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), OUT_PARAM(pValue), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadNumber(pValue, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadNumber(long* pValue, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadNumber"), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), OUT_PARAM(pValue), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadNumber(pValue, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadNumber(BYTE* pValue, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadNumber"), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), OUT_PARAM(pValue), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadNumber(pValue, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadNumber(NtlAsciiType type, VARIANT* pData, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadNumber"), IN_PARAM(type), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), OUT_PARAM(pData), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadNumber(type, pData, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadList(double* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadList"), SIZED_OUT_PARAM(pValues, lMaxLength), IN_PARAM(lMaxLength), OUT_PARAM(plActualLength), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadList(pValues, lMaxLength, plActualLength, strListSeparator, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadList(long* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadList"), SIZED_OUT_PARAM(pValues, lMaxLength), IN_PARAM(lMaxLength), OUT_PARAM(plActualLength), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadList(pValues, lMaxLength, plActualLength, strListSeparator, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadList(BYTE* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadList"), SIZED_OUT_PARAM(pValues, lMaxLength), IN_PARAM(lMaxLength), OUT_PARAM(plActualLength), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadList(pValues, lMaxLength, plActualLength, strListSeparator, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadList(CComBSTR* pValues, long lMaxLength, long* plActualLength, const CString& strListSeparator, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadList"), SIZED_OUT_PARAM(pValues, lMaxLength), IN_PARAM(lMaxLength), OUT_PARAM(plActualLength), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadList(pValues, lMaxLength, plActualLength, strListSeparator, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadList(NtlAsciiType type, const CString& strListSeparator, VARIANT* pData, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadList"), IN_PARAM(type), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), OUT_PARAM(pData), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadList(type, strListSeparator, pData, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadList(NtlAsciiType type, const CString& strListSeparator, SAFEARRAY** pData, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadList"), IN_PARAM(type), IN_CSTRING_PARAM(strListSeparator), IN_PARAM(lTimeout), OUT_PARAM(pData), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadList(type, strListSeparator, pData, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadIEEEBlock(double* pValues, long lMaxLength, long* plActualLength, bool bSeekToBlock, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadIEEEBlock"), SIZED_OUT_PARAM(pValues, lMaxLength), IN_PARAM(lMaxLength), OUT_PARAM(plActualLength), IN_PARAM(bSeekToBlock), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadIEEEBlock(pValues, lMaxLength, plActualLength, bSeekToBlock, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadIEEEBlock(long* pValues, long lMaxLength, long* plActualLength, bool bSeekToBlock, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadIEEEBlock"), SIZED_OUT_PARAM(pValues, lMaxLength), IN_PARAM(lMaxLength), OUT_PARAM(plActualLength), IN_PARAM(bSeekToBlock), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadIEEEBlock(pValues, lMaxLength, plActualLength, bSeekToBlock, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadIEEEBlock(BYTE* pValues, long lMaxLength, long* plActualLength, bool bSeekToBlock, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadIEEEBlock"), SIZED_OUT_PARAM(pValues, lMaxLength), IN_PARAM(lMaxLength), OUT_PARAM(plActualLength), IN_PARAM(bSeekToBlock), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadIEEEBlock(pValues, lMaxLength, plActualLength, bSeekToBlock, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadIEEEBlock(NtlBinaryType type, VARIANT* pData, bool bSeekToBlock, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadIEEEBlock"), IN_PARAM(type), OUT_PARAM(pData), IN_PARAM(bSeekToBlock), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadIEEEBlock(type, pData, bSeekToBlock, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedReadIEEEBlock(NtlBinaryType type, SAFEARRAY** pData, bool bSeekToBlock, bool bFlushToEnd, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedReadIEEEBlock"), IN_PARAM(type), OUT_PARAM(pData), IN_PARAM(bSeekToBlock), IN_PARAM(bFlushToEnd), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedReadIEEEBlock(type, pData, bSeekToBlock, bFlushToEnd, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedFlushWrite(bool bSendEND, long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedFlushWrite"), IN_PARAM(bSendEND), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedFlushWrite(bSendEND, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedFlushRead(long lTimeout)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedFlushRead"), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvFormattedFlushRead(lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::FormattedSetBufferSize(NtlBufferMask mask, long lSize)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("FormattedSetBufferSize"), IN_PARAM(mask), IN_PARAM(lSize), NULL);

	hr = pT->GetRoot()->ioprvFormattedSetBufferSize(mask, lSize);

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// Wrappers around the IRegister interface

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterIn8(UINT16 space, UINT32 offset, UINT8* val)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterIn8"), IN_PARAM(space), IN_PARAM(offset), OUT_PARAM(val));

	hr = pT->GetRoot()->ioprvRegisterIn8(space, offset, val);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterOut8(UINT16 space, UINT32 offset, UINT8 val)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterOut8"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(val));

	hr = pT->GetRoot()->ioprvRegisterOut8(space, offset, val);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterIn16(UINT16 space, UINT32 offset, UINT16* val)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterIn16"), IN_PARAM(space), IN_PARAM(offset), OUT_PARAM(val));

	hr = pT->GetRoot()->ioprvRegisterIn16(space, offset, val);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterOut16(UINT16 space, UINT32 offset, UINT16 val)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterOut16"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(val));

	hr = pT->GetRoot()->ioprvRegisterOut16(space, offset, val);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterIn32(UINT16 space, UINT32 offset, UINT32* val)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterIn32"), IN_PARAM(space), IN_PARAM(offset), OUT_PARAM(val));

	hr = pT->GetRoot()->ioprvRegisterIn32(space, offset, val);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterOut32(UINT16 space, UINT32 offset, UINT32 val)
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterOut32"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(val));

	hr = pT->GetRoot()->ioprvRegisterOut32(space, offset, val);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterMoveIn8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[])
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterMoveIn8"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(length), SIZED_OUT_PARAM(buf, length));

	hr = pT->GetRoot()->ioprvRegisterMoveIn8(space, offset, length, buf);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterMoveOut8(UINT16 space, UINT32 offset, UINT32 length, UINT8 buf[])
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterMoveOut8"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(length), SIZED_IN_PARAM(buf, length));

	hr = pT->GetRoot()->ioprvRegisterMoveOut8(space, offset, length, buf);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterMoveIn16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[])
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterMoveIn16"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(length), SIZED_OUT_PARAM(buf, length));

	hr = pT->GetRoot()->ioprvRegisterMoveIn16(space, offset, length, buf);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterMoveOut16(UINT16 space, UINT32 offset, UINT32 length, UINT16 buf[])
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterMoveOut16"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(length), SIZED_IN_PARAM(buf, length));

	hr = pT->GetRoot()->ioprvRegisterMoveOut16(space, offset, length, buf);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterMoveIn32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[])
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterMoveIn32"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(length), SIZED_OUT_PARAM(buf, length));

	hr = pT->GetRoot()->ioprvRegisterMoveIn32(space, offset, length, buf);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::RegisterMoveOut32(UINT16 space, UINT32 offset, UINT32 length, UINT32 buf[])
{
	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("RegisterMoveOut32"), IN_PARAM(space), IN_PARAM(offset), IN_PARAM(length), SIZED_IN_PARAM(buf, length));

	hr = pT->GetRoot()->ioprvRegisterMoveOut32(space, offset, length, buf);

	return hr;
}

///////////////////////////////////////////////////////////////////////////////
// High level functions for pre-built commands

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrPrintCommand()
{
	HRESULT hr = S_OK;

	CString strCommand = GetInstrCommand();

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrPrintCommand"), IN_CSTRING_PARAM(strCommand), NULL);

	hr = pT->GetRoot()->ioprvInstrWrite(strCommand);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrPrintCommandNoPoll()
{
	HRESULT hr = S_OK;

	CString strCommand = GetInstrCommand();

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrPrintCommandNoPoll"), IN_CSTRING_PARAM(strCommand), NULL);

	hr = pT->GetRoot()->ioprvInstrWriteNoPoll(strCommand);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommand(double* pdResult, long lTimeout)
{
	HRESULT hr = S_OK;

	CString strCommand = GetInstrCommand();

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryCommand"), IN_CSTRING_PARAM(strCommand), IN_PARAM(lTimeout), OUT_PARAM(pdResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCommand, pdResult, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommand(float* pfResult, long lTimeout)
{
	HRESULT hr = S_OK;

	double dResult = 0;
	hr = InstrQueryCommand(&dResult, lTimeout);
	*pfResult = (float)dResult;

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommand(long* plResult, long lTimeout)
{
	HRESULT hr = S_OK;

	CString strCommand = GetInstrCommand();

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryCommand"), IN_CSTRING_PARAM(strCommand), IN_PARAM(lTimeout), OUT_PARAM(plResult), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCommand, plResult, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommand(short* psResult, long lTimeout)
{
	HRESULT hr = S_OK;

	long lResult = 0;
	hr = InstrQueryCommand(&lResult, lTimeout);
	*psResult = (short)lResult;

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommand(BYTE* pbResult, long lTimeout)
{
	HRESULT hr = S_OK;

	long lResult = 0;
	hr = InstrQueryCommand(&lResult, lTimeout);
	*pbResult = (BYTE)lResult;

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommand(CString& strResult, long cchDesired, long lTimeout)
{
	HRESULT hr = S_OK;

	CString strCommand = GetInstrCommand();

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryCommand"), IN_CSTRING_PARAM(strCommand), IN_PARAM(cchDesired), IN_PARAM(lTimeout), NULL);

	hr = pT->GetRoot()->ioprvInstrQuery(strCommand, strResult, cchDesired, lTimeout);

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommand(BSTR* pbstrResult, long lTimeout)
{
	HRESULT hr = S_OK;

	CString strResult;
	hr = InstrQueryCommand(strResult, DEFAULT_STRING_LENGTH, lTimeout);
	*pbstrResult = CComBSTR(strResult).Detach();

	return hr;
}

template <class DriverClass, class RootClass>
HRESULT CDriverIOManager<DriverClass, RootClass>::InstrQueryCommandBool(VARIANT_BOOL* plResult, long lTimeout)
{
	if (plResult == NULL)
		return E_POINTER;
	*plResult = VARIANT_FALSE;

	HRESULT hr = S_OK;

	DriverClass* pT = static_cast<DriverClass*>(this);
	CMethodTrace mt(pT, _T("CDriverIOManager"), _T("InstrQueryCommandBool"), IN_PARAM(lTimeout), OUT_PARAM(plResult), NULL);

	CString strBoolString;
	hr = InstrQueryCommand(strBoolString, MAX_BOOL_STRING, lTimeout);
	if (SUCCEEDED(hr))
	{
		if (strBoolString == GetBooleanTrueCommand())
		{
			*plResult = VARIANT_TRUE;
		}
		else if (strBoolString == GetBooleanFalseCommand())
		{
			*plResult = VARIANT_FALSE;
		}
		else
		{
			hr = pT->ReportError(IDS_E_IVI_UNEXPECTED_RESPONSE);
		}
	}

	return hr;
}

#endif // #endif __NTLIO_INCLUDED
