home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Active Template Library.
- // Copyright (C) 1996-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Active Template Library Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Active Template Library product.
-
- // ATLDBCLI.H : ATL consumer code for OLEDB
-
- #ifndef __ATLDBCLI_H_
- #define __ATLDBCLI_H_
-
- #ifdef __BORLANDC__
- #ifdef _BCB_ATL_DEBUG
- #define _DEBUG
- #endif
- #endif
-
- #ifndef __cplusplus
- #error ATL requires C++ compilation (use a .cpp suffix)
- #endif
-
- #ifndef _ATLBASE_H
- #include "atlbase.h"
- #endif
-
- #ifndef __oledb_h__
- #include <oledb.h>
- #endif // __oledb_h__
-
- #include <msdaguid.h>
- #include <msdasc.h>
-
- namespace ATL
- {
-
- #define DEFINE_OLEDB_TYPE_FUNCTION(ctype, oledbtype) \
- inline DBTYPE _GetOleDBType(ctype&) \
- { \
- return oledbtype; \
- }
- inline DBTYPE _GetOleDBType(BYTE[])
- {
- return DBTYPE_BYTES;
- }
- inline DBTYPE _GetOleDBType(CHAR[])
- {
- return DBTYPE_STR;
- }
- inline DBTYPE _GetOleDBType(WCHAR[])
- {
- return DBTYPE_WSTR;
- }
-
- DEFINE_OLEDB_TYPE_FUNCTION(signed char ,DBTYPE_I1)
- DEFINE_OLEDB_TYPE_FUNCTION(SHORT ,DBTYPE_I2) // DBTYPE_BOOL
- DEFINE_OLEDB_TYPE_FUNCTION(int ,DBTYPE_I4)
- DEFINE_OLEDB_TYPE_FUNCTION(LONG ,DBTYPE_I4) // DBTYPE_ERROR (SCODE)
- DEFINE_OLEDB_TYPE_FUNCTION(LARGE_INTEGER ,DBTYPE_I8) // DBTYPE_CY
- DEFINE_OLEDB_TYPE_FUNCTION(BYTE ,DBTYPE_UI1)
- DEFINE_OLEDB_TYPE_FUNCTION(unsigned short ,DBTYPE_UI2)
- DEFINE_OLEDB_TYPE_FUNCTION(unsigned int ,DBTYPE_UI4)
- DEFINE_OLEDB_TYPE_FUNCTION(unsigned long ,DBTYPE_UI4)
- DEFINE_OLEDB_TYPE_FUNCTION(ULARGE_INTEGER ,DBTYPE_UI8)
- DEFINE_OLEDB_TYPE_FUNCTION(float ,DBTYPE_R4)
- DEFINE_OLEDB_TYPE_FUNCTION(double ,DBTYPE_R8) // DBTYPE_DATE
- DEFINE_OLEDB_TYPE_FUNCTION(DECIMAL ,DBTYPE_DECIMAL)
- DEFINE_OLEDB_TYPE_FUNCTION(DB_NUMERIC ,DBTYPE_NUMERIC)
- DEFINE_OLEDB_TYPE_FUNCTION(VARIANT ,DBTYPE_VARIANT)
- DEFINE_OLEDB_TYPE_FUNCTION(IDispatch* ,DBTYPE_IDISPATCH)
- DEFINE_OLEDB_TYPE_FUNCTION(IUnknown* ,DBTYPE_IUNKNOWN)
- DEFINE_OLEDB_TYPE_FUNCTION(GUID ,DBTYPE_GUID)
- DEFINE_OLEDB_TYPE_FUNCTION(SAFEARRAY* ,DBTYPE_ARRAY)
- DEFINE_OLEDB_TYPE_FUNCTION(DBVECTOR ,DBTYPE_VECTOR)
- DEFINE_OLEDB_TYPE_FUNCTION(DBDATE ,DBTYPE_DBDATE)
- DEFINE_OLEDB_TYPE_FUNCTION(DBTIME ,DBTYPE_DBTIME)
- DEFINE_OLEDB_TYPE_FUNCTION(DBTIMESTAMP ,DBTYPE_DBTIMESTAMP)
- DEFINE_OLEDB_TYPE_FUNCTION(FILETIME ,DBTYPE_FILETIME)
- DEFINE_OLEDB_TYPE_FUNCTION(DBFILETIME ,DBTYPE_DBFILETIME)
- DEFINE_OLEDB_TYPE_FUNCTION(PROPVARIANT ,DBTYPE_PROPVARIANT)
- DEFINE_OLEDB_TYPE_FUNCTION(DB_VARNUMERIC ,DBTYPE_VARNUMERIC)
-
- // Internal structure containing the accessor handle and a flag
- // indicating whether the data for the accessor is automatically
- // retrieved
- struct _ATL_ACCESSOR_INFO
- {
- HACCESSOR hAccessor;
- bool bAutoAccessor;
- };
-
- class _CNoOutputColumns
- {
- public:
- static bool HasOutputColumns()
- {
- return false;
- }
- static ULONG _GetNumAccessors()
- {
- return 0;
- }
- static HRESULT _GetBindEntries(ULONG*, DBBINDING*, ULONG, bool*, BYTE* pBuffer = NULL)
- {
- pBuffer;
- return E_FAIL;
- }
- };
-
- class _CNoParameters
- {
- public:
- static bool HasParameters()
- {
- return false;
- }
- static HRESULT _GetParamEntries(ULONG*, DBBINDING*, BYTE* pBuffer = NULL)
- {
- pBuffer;
- return E_FAIL;
- }
- };
-
- class _CNoCommand
- {
- public:
- static HRESULT GetDefaultCommand(LPCTSTR* /*ppszCommand*/)
- {
- return S_OK;
- }
- };
-
- typedef _CNoOutputColumns _OutputColumnsClass;
- typedef _CNoParameters _ParamClass;
- typedef _CNoCommand _CommandClass;
-
- #define BEGIN_ACCESSOR_MAP(x, num) \
- public: \
- typedef x _classtype; \
- typedef x _OutputColumnsClass; \
- static ULONG _GetNumAccessors() { return num; } \
- static bool HasOutputColumns() { return true; } \
- /* If pBindings == NULL means we only return the column number */ \
- /* If pBuffer != NULL then it points to the accessor buffer and */ \
- /* we release any appropriate memory e.g. BSTR's or interface pointers */ \
- inline static HRESULT _GetBindEntries(ULONG* pColumns, DBBINDING *pBinding, ULONG nAccessor, bool* pAuto, BYTE* pBuffer = NULL) \
- { \
- ATLASSERT(pColumns != NULL); \
- DBPARAMIO eParamIO = DBPARAMIO_NOTPARAM; \
- ULONG nColumns = 0; \
- pBuffer;
-
- #define BEGIN_ACCESSOR(num, bAuto) \
- if (nAccessor == num) \
- { \
- if (pBinding != NULL) \
- *pAuto = bAuto;
-
- #define END_ACCESSOR() \
- } \
- else
-
- #define END_ACCESSOR_MAP() \
- ; \
- *pColumns = nColumns; \
- return S_OK; \
- }
-
- #define BEGIN_COLUMN_MAP(x) \
- BEGIN_ACCESSOR_MAP(x, 1) \
- BEGIN_ACCESSOR(0, true)
-
- #define END_COLUMN_MAP() \
- END_ACCESSOR() \
- END_ACCESSOR_MAP()
-
- #define offsetbuf(m) offsetof(_classtype, m)
- #define _OLEDB_TYPE(data) _GetOleDBType(((_classtype*)0)->data)
- #define _SIZE_TYPE(data) sizeof(((_classtype*)0)->data)
-
- #define _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, nPrecision, nScale, dataOffset, lengthOffset, statusOffset) \
- if (pBuffer != NULL) \
- { \
- CAccessorBase::FreeType(wType, pBuffer + dataOffset); \
- } \
- else if (pBinding != NULL) \
- { \
- CAccessorBase::Bind(pBinding, nOrdinal, wType, nLength, nPrecision, nScale, eParamIO, \
- dataOffset, lengthOffset, statusOffset); \
- pBinding++; \
- } \
- nColumns++;
-
- #define COLUMN_ENTRY_EX(nOrdinal, wType, nLength, nPrecision, nScale, data, length, status) \
- _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
-
- #define COLUMN_ENTRY_TYPE(nOrdinal, wType, data) \
- COLUMN_ENTRY_TYPE_SIZE(nOrdinal, wType, _SIZE_TYPE(data), data)
-
- #define COLUMN_ENTRY_TYPE_SIZE(nOrdinal, wType, nLength, data) \
- _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, 0, 0, offsetbuf(data), 0, 0)
-
-
- // Standard macros where type and size is worked out
- #define COLUMN_ENTRY(nOrdinal, data) \
- COLUMN_ENTRY_TYPE(nOrdinal, _OLEDB_TYPE(data), data)
-
- #define COLUMN_ENTRY_LENGTH(nOrdinal, data, length) \
- _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), 0)
-
- #define COLUMN_ENTRY_STATUS(nOrdinal, data, status) \
- _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), 0, offsetbuf(status))
-
- #define COLUMN_ENTRY_LENGTH_STATUS(nOrdinal, data, length, status) \
- _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), offsetbuf(status))
-
-
- // Follow macros are used if precision and scale need to be specified
- #define COLUMN_ENTRY_PS(nOrdinal, nPrecision, nScale, data) \
- _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, 0)
-
- #define COLUMN_ENTRY_PS_LENGTH(nOrdinal, nPrecision, nScale, data, length) \
- _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), 0)
-
- #define COLUMN_ENTRY_PS_STATUS(nOrdinal, nPrecision, nScale, data, status) \
- _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, offsetbuf(status))
-
- #define COLUMN_ENTRY_PS_LENGTH_STATUS(nOrdinal, nPrecision, nScale, data, length, status) \
- _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
-
-
- #define BOOKMARK_ENTRY(variable) \
- COLUMN_ENTRY_TYPE_SIZE(0, DBTYPE_BYTES, _SIZE_TYPE(variable##.m_rgBuffer), variable##.m_rgBuffer)
-
- #define _BLOB_ENTRY_CODE(nOrdinal, IID, flags, dataOffset, statusOffset) \
- if (pBuffer != NULL) \
- { \
- CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
- } \
- else if (pBinding != NULL) \
- { \
- DBOBJECT* pObject = NULL; \
- ATLTRY(pObject = new DBOBJECT); \
- if (pObject == NULL) \
- return E_OUTOFMEMORY; \
- pObject->dwFlags = flags; \
- pObject->iid = IID; \
- CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN, sizeof(IUnknown*), 0, 0, eParamIO, \
- dataOffset, 0, statusOffset, pObject); \
- pBinding++; \
- } \
- nColumns++;
-
- #define BLOB_ENTRY(nOrdinal, IID, flags, data) \
- _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), 0);
-
- #define BLOB_ENTRY_STATUS(nOrdinal, IID, flags, data, status) \
- _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), offsetbuf(status));
-
- #define BEGIN_PARAM_MAP(x) \
- public: \
- typedef x _classtype; \
- typedef x _ParamClass; \
- static bool HasParameters() { return true; } \
- static HRESULT _GetParamEntries(ULONG* pColumns, DBBINDING *pBinding, BYTE* pBuffer = NULL) \
- { \
- ATLASSERT(pColumns != NULL); \
- DBPARAMIO eParamIO = DBPARAMIO_INPUT; \
- int nColumns = 0; \
- pBuffer;
-
- #define END_PARAM_MAP() \
- *pColumns = nColumns; \
- return S_OK; \
- }
-
- #define SET_PARAM_TYPE(type) \
- eParamIO = type;
-
- #define DEFINE_COMMAND(x, szCommand) \
- typedef x _CommandClass; \
- static HRESULT GetDefaultCommand(LPCTSTR* ppszCommand) \
- { \
- *ppszCommand = szCommand; \
- return S_OK; \
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CDBErrorInfo
-
- class CDBErrorInfo
- {
- public:
- // Use to get the number of error record when you want to explicitly check that
- // the passed interface set the error information
- HRESULT GetErrorRecords(IUnknown* pUnk, const IID& iid, ULONG* pcRecords)
- {
- CComPtr<ISupportErrorInfo> spSupportErrorInfo;
- #ifdef __BORLANDC__
- HRESULT hr = pUnk->QueryInterface((void **) &spSupportErrorInfo);
- #else
- HRESULT hr = pUnk->QueryInterface(&spSupportErrorInfo);
- #endif
- if (FAILED(hr))
- return hr;
-
- hr = spSupportErrorInfo->InterfaceSupportsErrorInfo(iid);
- if (FAILED(hr))
- return hr;
-
- return GetErrorRecords(pcRecords);
- }
- // Use to get the number of error records
- HRESULT GetErrorRecords(ULONG* pcRecords)
- {
- ATLASSERT(pcRecords != NULL);
- HRESULT hr;
- m_spErrorInfo.Release();
- m_spErrorRecords.Release();
- hr = ::GetErrorInfo(0, &m_spErrorInfo);
- if (hr == S_FALSE)
- return E_FAIL;
-
- hr = m_spErrorInfo->QueryInterface(IID_IErrorRecords, (void**)&m_spErrorRecords);
- if (FAILED(hr))
- {
- // Well we got the IErrorInfo so we'll just treat that as
- // the one record
- *pcRecords = 1;
- return S_OK;
- }
-
- return m_spErrorRecords->GetRecordCount(pcRecords);
- }
- // Get the error information for the passed record number. GetErrorRecords must
- // be called before this function is called.
- HRESULT GetAllErrorInfo(ULONG ulRecordNum, LCID lcid, BSTR* pbstrDescription,
- BSTR* pbstrSource = NULL, GUID* pguid = NULL, DWORD* pdwHelpContext = NULL,
- BSTR* pbstrHelpFile = NULL) const
- {
- CComPtr<IErrorInfo> spErrorInfo;
-
- // If we have the IErrorRecords interface pointer then use it, otherwise
- // we'll just default to the IErrorInfo we have already retrieved in the call
- // to GetErrorRecords
- if (m_spErrorRecords != NULL)
- {
- HRESULT hr = m_spErrorRecords->GetErrorInfo(ulRecordNum, lcid, &spErrorInfo);
- if (FAILED(hr))
- return hr;
- }
- else
- {
- ATLASSERT(m_spErrorInfo != NULL);
- spErrorInfo = m_spErrorInfo;
- }
-
- if (pbstrDescription != NULL)
- spErrorInfo->GetDescription(pbstrDescription);
-
- if (pguid != NULL)
- spErrorInfo->GetGUID(pguid);
-
- if (pdwHelpContext != NULL)
- spErrorInfo->GetHelpContext(pdwHelpContext);
-
- if (pbstrHelpFile != NULL)
- spErrorInfo->GetHelpFile(pbstrHelpFile);
-
- if (pbstrSource != NULL)
- spErrorInfo->GetSource(pbstrSource);
-
- return S_OK;
- }
- // Get the error information for the passed record number
- HRESULT GetBasicErrorInfo(ULONG ulRecordNum, ERRORINFO* pErrorInfo) const
- {
- return m_spErrorRecords->GetBasicErrorInfo(ulRecordNum, pErrorInfo);
- }
- // Get the custom error object for the passed record number
- HRESULT GetCustomErrorObject(ULONG ulRecordNum, REFIID riid, IUnknown** ppObject) const
- {
- return m_spErrorRecords->GetCustomErrorObject(ulRecordNum, riid, ppObject);
- }
- // Get the IErrorInfo interface for the passed record number
- HRESULT GetErrorInfo(ULONG ulRecordNum, LCID lcid, IErrorInfo** ppErrorInfo) const
- {
- return m_spErrorRecords->GetErrorInfo(ulRecordNum, lcid, ppErrorInfo);
- }
- // Get the error parameters for the passed record number
- HRESULT GetErrorParameters(ULONG ulRecordNum, DISPPARAMS* pdispparams) const
- {
- return m_spErrorRecords->GetErrorParameters(ulRecordNum, pdispparams);
- }
-
- // Implementation
- CComPtr<IErrorInfo> m_spErrorInfo;
- CComPtr<IErrorRecords> m_spErrorRecords;
- };
-
- #ifdef _DEBUG
- inline void AtlTraceErrorRecords(HRESULT hrErr = S_OK)
- {
- CDBErrorInfo ErrorInfo;
- ULONG cRecords;
- HRESULT hr;
- ULONG i;
- CComBSTR bstrDesc, bstrHelpFile, bstrSource;
- GUID guid;
- DWORD dwHelpContext;
- WCHAR wszGuid[40];
- USES_CONVERSION;
-
- // If the user passed in an HRESULT then trace it
- if (hrErr != S_OK)
- ATLTRACE2(atlTraceDBClient, 0, _T("OLE DB Error Record dump for hr = 0x%x\n"), hrErr);
-
- LCID lcLocale = GetSystemDefaultLCID();
-
- hr = ErrorInfo.GetErrorRecords(&cRecords);
- if (FAILED(hr) && ErrorInfo.m_spErrorInfo == NULL)
- {
- ATLTRACE2(atlTraceDBClient, 0, _T("No OLE DB Error Information found: hr = 0x%x\n"), hr);
- }
- else
- {
- for (i = 0; i < cRecords; i++)
- {
- hr = ErrorInfo.GetAllErrorInfo(i, lcLocale, &bstrDesc, &bstrSource, &guid,
- &dwHelpContext, &bstrHelpFile);
- if (FAILED(hr))
- {
- ATLTRACE2(atlTraceDBClient, 0,
- _T("OLE DB Error Record dump retrieval failed: hr = 0x%x\n"), hr);
- return;
- }
- StringFromGUID2(guid, wszGuid, sizeof(wszGuid) / sizeof(WCHAR));
- ATLTRACE2(atlTraceDBClient, 0,
- _T("Row #: %4d Source: \"%s\" Description: \"%s\" Help File: \"%s\" Help Context: %4d GUID: %s\n"),
- i, OLE2T(bstrSource), OLE2T(bstrDesc), OLE2T(bstrHelpFile), dwHelpContext, OLE2T(wszGuid));
- bstrSource.Empty();
- bstrDesc.Empty();
- bstrHelpFile.Empty();
- }
- ATLTRACE2(atlTraceDBClient, 0, _T("OLE DB Error Record dump end\n"));
- }
- }
- #else
- inline void AtlTraceErrorRecords(HRESULT hrErr = S_OK) { hrErr; }
- #endif
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CDBPropSet
-
- class CDBPropSet : public tagDBPROPSET
- {
- public:
- CDBPropSet()
- {
- rgProperties = NULL;
- cProperties = 0;
- }
- CDBPropSet(const GUID& guid)
- {
- rgProperties = NULL;
- cProperties = 0;
- guidPropertySet = guid;
- }
- CDBPropSet(const CDBPropSet& propset)
- {
- InternalCopy(propset);
- }
- ~CDBPropSet()
- {
- for (ULONG i = 0; i < cProperties; i++)
- VariantClear(&rgProperties[i].vValue);
-
- CoTaskMemFree(rgProperties);
- }
- CDBPropSet& operator=(CDBPropSet& propset)
- {
- this->~CDBPropSet();
- InternalCopy(propset);
- return *this;
- }
- // Set the GUID of the property set this class represents.
- // Use if you didn't pass the GUID to the constructor.
- void SetGUID(const GUID& guid)
- {
- guidPropertySet = guid;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, const VARIANT& var)
- {
- HRESULT hr;
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- hr = ::VariantCopy(&(rgProperties[cProperties].vValue), const_cast<VARIANT*>(&var));
- if (FAILED(hr))
- return false;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, LPCSTR szValue)
- {
- USES_CONVERSION;
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_BSTR;
- rgProperties[cProperties].vValue.bstrVal = SysAllocString(A2COLE(szValue));
- if (rgProperties[cProperties].vValue.bstrVal == NULL)
- return false;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, LPCWSTR szValue)
- {
- USES_CONVERSION;
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_BSTR;
- rgProperties[cProperties].vValue.bstrVal = SysAllocString(W2COLE(szValue));
- if (rgProperties[cProperties].vValue.bstrVal == NULL)
- return false;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, bool bValue)
- {
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_BOOL;
- #pragma warning(disable: 4310) // cast truncates constant value
- rgProperties[cProperties].vValue.boolVal = (bValue) ? VARIANT_TRUE : VARIANT_FALSE;
- #pragma warning(default: 4310)
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, BYTE bValue)
- {
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_UI1;
- rgProperties[cProperties].vValue.bVal = bValue;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, short nValue)
- {
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_I2;
- rgProperties[cProperties].vValue.iVal = nValue;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, long nValue)
- {
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_I4;
- rgProperties[cProperties].vValue.lVal = nValue;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, float fltValue)
- {
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_R4;
- rgProperties[cProperties].vValue.fltVal = fltValue;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, double dblValue)
- {
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_R8;
- rgProperties[cProperties].vValue.dblVal = dblValue;
- cProperties++;
- return true;
- }
- // Add the passed property to the property set
- bool AddProperty(DWORD dwPropertyID, CY cyValue)
- {
- if (!Add())
- return false;
- rgProperties[cProperties].dwPropertyID = dwPropertyID;
- rgProperties[cProperties].vValue.vt = VT_CY;
- rgProperties[cProperties].vValue.cyVal = cyValue;
- cProperties++;
- return true;
- }
- // Implementation
- // Create memory to add a new property
- bool Add()
- {
- rgProperties = (DBPROP*)CoTaskMemRealloc(rgProperties, (cProperties + 1) * sizeof(DBPROP));
- if (rgProperties != NULL)
- {
- rgProperties[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED;
- rgProperties[cProperties].colid = DB_NULLID;
- rgProperties[cProperties].vValue.vt = VT_EMPTY;
- return true;
- }
- else
- return false;
- }
- // Copies in the passed value now it this value been cleared
- void InternalCopy(const CDBPropSet& propset)
- {
- cProperties = propset.cProperties;
- guidPropertySet = propset.guidPropertySet;
- rgProperties = (DBPROP*)CoTaskMemAlloc(cProperties * sizeof(DBPROP));
- if (rgProperties != NULL)
- {
- for (ULONG i = 0; i < cProperties; i++)
- {
- rgProperties[i].dwPropertyID = propset.rgProperties[i].dwPropertyID;
- rgProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
- rgProperties[i].colid = DB_NULLID;
- rgProperties[i].vValue.vt = VT_EMPTY;
- VariantCopy(&rgProperties[i].vValue, &propset.rgProperties[i].vValue);
- }
- }
- else
- {
- // The memory allocation failed so set the count
- // of properties to zero
- cProperties = 0;
- }
- }
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CDBPropIDSet
-
- class CDBPropIDSet : public tagDBPROPIDSET
- {
- // Constructors and Destructors
- public:
- CDBPropIDSet()
- {
- rgPropertyIDs = NULL;
- cPropertyIDs = 0;
- }
- CDBPropIDSet(const GUID& guid)
- {
- rgPropertyIDs = NULL;
- cPropertyIDs = 0;
- guidPropertySet = guid;
- }
- CDBPropIDSet(const CDBPropIDSet& propidset)
- {
- InternalCopy(propidset);
- }
- ~CDBPropIDSet()
- {
- if (rgPropertyIDs != NULL)
- free(rgPropertyIDs);
- }
- CDBPropIDSet& operator=(CDBPropIDSet& propset)
- {
- this->~CDBPropIDSet();
- InternalCopy(propset);
- return *this;
- }
- // Set the GUID of the property ID set
- void SetGUID(const GUID& guid)
- {
- guidPropertySet = guid;
- }
- // Add a property ID to the set
- bool AddPropertyID(DBPROPID propid)
- {
- if (!Add())
- return false;
- rgPropertyIDs[cPropertyIDs] = propid;
- cPropertyIDs++;
- return true;
- }
- // Implementation
- bool Add()
- {
- rgPropertyIDs = (DBPROPID*)realloc(rgPropertyIDs, (cPropertyIDs + 1) * sizeof(DBPROPID));
- return (rgPropertyIDs != NULL) ? true : false;
- }
- void InternalCopy(const CDBPropIDSet& propidset)
- {
- cPropertyIDs = propidset.cPropertyIDs;
- guidPropertySet = propidset.guidPropertySet;
- rgPropertyIDs = (DBPROPID*)malloc(cPropertyIDs * sizeof(DBPROPID));
- if (rgPropertyIDs != NULL)
- {
- for (ULONG i = 0; i < cPropertyIDs; i++)
- rgPropertyIDs[i] = propidset.rgPropertyIDs[i];
- }
- else
- {
- // The memory allocation failed so set the count
- // of properties to zero
- cPropertyIDs = 0;
- }
- }
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CBookmarkBase
-
- class ATL_NO_VTABLE CBookmarkBase
- {
- public:
- virtual ULONG GetSize() const = 0;
- virtual BYTE* GetBuffer() const = 0;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CBookmark
-
- template <ULONG nSize = 0>
- class CBookmark : public CBookmarkBase
- {
- public:
- virtual ULONG GetSize() const { return nSize; }
- virtual BYTE* GetBuffer() const { return (BYTE*)m_rgBuffer; }
-
- // Implementation
- BYTE m_rgBuffer[nSize];
- };
-
-
- // Size of 0 means that the memory for the bookmark will be allocated
- // at run time.
- template <>
- class CBookmark<0> : public CBookmarkBase
- {
- public:
- CBookmark()
- {
- m_nSize = 0;
- m_pBuffer = NULL;
- }
- CBookmark(ULONG nSize)
- {
- m_pBuffer = NULL;
- ATLTRY(m_pBuffer = new BYTE[nSize]);
- m_nSize = (m_pBuffer == NULL) ? 0 : nSize;
- }
- ~CBookmark()
- {
- delete [] m_pBuffer;
- }
- CBookmark& operator=(const CBookmark& bookmark)
- {
- SetBookmark(bookmark.GetSize(), bookmark.GetBuffer());
- return *this;
- }
- virtual ULONG GetSize() const { return m_nSize; }
- virtual BYTE* GetBuffer() const { return m_pBuffer; }
- // Sets the bookmark to the passed value
- HRESULT SetBookmark(ULONG nSize, BYTE* pBuffer)
- {
- ATLASSERT(pBuffer != NULL);
- delete [] m_pBuffer;
- m_pBuffer = NULL;
- ATLTRY(m_pBuffer = new BYTE[nSize]);
- if (m_pBuffer != NULL)
- {
- memcpy(m_pBuffer, pBuffer, nSize);
- m_nSize = nSize;
- return S_OK;
- }
- else
- {
- m_nSize = 0;
- return E_OUTOFMEMORY;
- }
- }
- ULONG m_nSize;
- BYTE* m_pBuffer;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CAccessorBase
-
- class CAccessorBase
- {
- public:
- CAccessorBase()
- {
- m_pAccessorInfo = NULL;
- m_nAccessors = 0;
- m_pBuffer = NULL;
- }
- void Close()
- {
- // If Close is called then ReleaseAccessors must have been
- // called first
- ATLASSERT(m_nAccessors == 0);
- ATLASSERT(m_pAccessorInfo == NULL);
- }
- // Get the number of accessors that have been created
- ULONG GetNumAccessors() const { return m_nAccessors; }
- // Get the handle of the passed accessor (offset from 0)
- HACCESSOR GetHAccessor(ULONG nAccessor) const
- {
- ATLASSERT(nAccessor<m_nAccessors);
- return m_pAccessorInfo[nAccessor].hAccessor;
- };
- // Called during Close to release the accessor information
- HRESULT ReleaseAccessors(IUnknown* pUnk)
- {
- ATLASSERT(pUnk != NULL);
- HRESULT hr = S_OK;
- if (m_nAccessors > 0)
- {
- CComPtr<IAccessor> spAccessor;
- hr = pUnk->QueryInterface(IID_IAccessor, (void**)&spAccessor);
- if (SUCCEEDED(hr))
- {
- ATLASSERT(m_pAccessorInfo != NULL);
- for (ULONG i = 0; i < m_nAccessors; i++)
- spAccessor->ReleaseAccessor(m_pAccessorInfo[i].hAccessor, NULL);
- }
- m_nAccessors = 0;
- delete [] m_pAccessorInfo;
- m_pAccessorInfo = NULL;
- }
- return hr;
- }
- // Returns true or false depending upon whether data should be
- // automatically retrieved for the passed accessor.
- bool IsAutoAccessor(ULONG nAccessor) const
- {
- ATLASSERT(nAccessor < m_nAccessors);
- ATLASSERT(m_pAccessorInfo != NULL);
- return m_pAccessorInfo[nAccessor].bAutoAccessor;
- }
-
- // Implementation
- // Used by the rowset class to find out where to place the data
- BYTE* GetBuffer() const
- {
- return m_pBuffer;
- }
- // Set the buffer that is used to retrieve the data
- void SetBuffer(BYTE* pBuffer)
- {
- m_pBuffer = pBuffer;
- }
-
- // Allocate internal memory for the passed number of accessors
- HRESULT AllocateAccessorMemory(int nAccessors)
- {
- // Can't be called twice without calling ReleaseAccessors first
- ATLASSERT(m_pAccessorInfo == NULL);
- m_nAccessors = nAccessors;
- m_pAccessorInfo = NULL;
- ATLTRY(m_pAccessorInfo = new _ATL_ACCESSOR_INFO[nAccessors]);
- if (m_pAccessorInfo == NULL)
- return E_OUTOFMEMORY;
- else
- return S_OK;
- }
- // BindParameters will be overriden if parameters are used
- HRESULT BindParameters(HACCESSOR*, ICommand*, void**) { return S_OK; }
-
- // Create an accessor for the passed binding information. The created accessor is
- // returned through the pHAccessor parameter.
- static HRESULT BindEntries(DBBINDING* pBindings, int nColumns, HACCESSOR* pHAccessor,
- ULONG nSize, IAccessor* pAccessor)
- {
- ATLASSERT(pBindings != NULL);
- ATLASSERT(pHAccessor != NULL);
- ATLASSERT(pAccessor != NULL);
- HRESULT hr;
- int i;
- DWORD dwAccessorFlags = (pBindings->eParamIO == DBPARAMIO_NOTPARAM) ?
- DBACCESSOR_ROWDATA : DBACCESSOR_PARAMETERDATA;
-
- #ifdef _DEBUG
- // In debug builds we will retrieve the status flags and trace out
- // any errors that may occur.
- DBBINDSTATUS* pStatus = NULL;
- ATLTRY(pStatus = new DBBINDSTATUS[nColumns]);
- hr = pAccessor->CreateAccessor(dwAccessorFlags, nColumns,
- pBindings, nSize, pHAccessor, pStatus);
- if (FAILED(hr) && pStatus != NULL)
- {
- for (i=0; i<nColumns; i++)
- {
- if (pStatus[i] != DBBINDSTATUS_OK)
- ATLTRACE2(atlTraceDBClient, 0, _T("Binding entry %d failed. Status: %d\n"), i, pStatus[i]);
- }
- }
- delete [] pStatus;
- #else
- hr = pAccessor->CreateAccessor(dwAccessorFlags, nColumns,
- pBindings, nSize, pHAccessor, NULL);
- #endif
- for (i=0; i<nColumns; i++)
- delete pBindings[i].pObject;
-
- return hr;
- }
- // Set up the binding structure pointed to by pBindings based upon
- // the other passed parameters.
- static void Bind(DBBINDING* pBinding, ULONG nOrdinal, DBTYPE wType,
- ULONG nLength, BYTE nPrecision, BYTE nScale, DBPARAMIO eParamIO,
- ULONG nDataOffset, ULONG nLengthOffset = NULL, ULONG nStatusOffset = NULL,
- DBOBJECT* pdbobject = NULL)
- {
- ATLASSERT(pBinding != NULL);
-
- // If we are getting a pointer to the data then let the provider
- // own the memory
- if (wType & DBTYPE_BYREF)
- pBinding->dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
- else
- pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
-
- pBinding->pObject = pdbobject;
-
- pBinding->eParamIO = eParamIO;
- pBinding->iOrdinal = nOrdinal;
- pBinding->wType = wType;
- pBinding->bPrecision = nPrecision;
- pBinding->bScale = nScale;
- pBinding->dwFlags = 0;
-
- pBinding->obValue = nDataOffset;
- pBinding->obLength = 0;
- pBinding->obStatus = 0;
- pBinding->pTypeInfo = NULL;
- pBinding->pBindExt = NULL;
- pBinding->cbMaxLen = nLength;
-
- pBinding->dwPart = DBPART_VALUE;
- if (nLengthOffset != NULL)
- {
- pBinding->dwPart |= DBPART_LENGTH;
- pBinding->obLength = nLengthOffset;
- }
- if (nStatusOffset != NULL)
- {
- pBinding->dwPart |= DBPART_STATUS;
- pBinding->obStatus = nStatusOffset;
- }
- }
-
- // Free memory if appropriate
- static inline void FreeType(DBTYPE wType, BYTE* pValue, IRowset* pRowset = NULL)
- {
- switch (wType)
- {
- case DBTYPE_BSTR:
- SysFreeString(*((BSTR*)pValue));
- break;
- case DBTYPE_VARIANT:
- VariantClear((VARIANT*)pValue);
- break;
- case DBTYPE_IUNKNOWN:
- case DBTYPE_IDISPATCH:
- (*(IUnknown**)pValue)->Release();
- break;
- case DBTYPE_ARRAY:
- SafeArrayDestroy((SAFEARRAY*)pValue);
- break;
-
- case DBTYPE_HCHAPTER:
- CComQIPtr<IChapteredRowset> spChapteredRowset = pRowset;
- if (spChapteredRowset != NULL)
- spChapteredRowset->ReleaseChapter(*(HCHAPTER*)pValue, NULL);
- break;
- }
- if ((wType & DBTYPE_VECTOR) && ~(wType & DBTYPE_BYREF))
- CoTaskMemFree(((DBVECTOR*)pValue)->ptr);
- }
-
- _ATL_ACCESSOR_INFO* m_pAccessorInfo;
- ULONG m_nAccessors;
- BYTE* m_pBuffer;
- };
-
- ///////////////////////////////////////////////////////////////////////////
- // class CRowset
-
- class CRowset
- {
- // Constructors and Destructors
- public:
- CRowset()
- {
- m_pAccessor = NULL;
- m_hRow = NULL;
- }
- CRowset(IRowset* pRowset)
- {
- m_spRowset = pRowset;
- CRowset();
- }
- ~CRowset()
- {
- Close();
- }
- // Release any retrieved row handles and then release the rowset
- void Close()
- {
- if (m_spRowset != NULL)
- {
- ReleaseRows();
- m_spRowset.Release();
- m_spRowsetChange.Release();
- }
- }
- // Addref the current row
- HRESULT AddRefRows()
- {
- ATLASSERT(m_spRowset != NULL);
- return m_spRowset->AddRefRows(1, &m_hRow, NULL, NULL);
- }
- // Release the current row
- HRESULT ReleaseRows()
- {
- ATLASSERT(m_spRowset != NULL);
- HRESULT hr = S_OK;
-
- if (m_hRow != NULL)
- {
- hr = m_spRowset->ReleaseRows(1, &m_hRow, NULL, NULL, NULL);
- m_hRow = NULL;
- }
- return hr;
- }
- // Compare two bookmarks with each other
- HRESULT Compare(const CBookmarkBase& bookmark1, const CBookmarkBase& bookmark2,
- DBCOMPARE* pComparison) const
- {
- ATLASSERT(m_spRowset != NULL);
- CComPtr<IRowsetLocate> spLocate;
- HRESULT hr = m_spRowset.QueryInterface(&spLocate);
- if (FAILED(hr))
- return hr;
-
- return spLocate->Compare(NULL, bookmark1.GetSize(), bookmark1.GetBuffer(),
- bookmark2.GetSize(), bookmark2.GetBuffer(), pComparison);
- }
- // Compare the passed hRow with the current row
- HRESULT IsSameRow(HROW hRow) const
- {
- ATLASSERT(m_spRowset != NULL);
- CComPtr<IRowsetIdentity> spRowsetIdentity;
- HRESULT hr = m_spRowset.QueryInterface(&spRowsetIdentity);
- if (FAILED(hr))
- return hr;
-
- return spRowsetIdentity->IsSameRow(m_hRow, hRow);
- }
- // Move to the previous record
- HRESULT MovePrev()
- {
- return MoveNext(-2, true);
- }
- // Move to the next record
- HRESULT MoveNext()
- {
- return MoveNext(0, true);
- }
- // Move lSkip records forward or backward
- HRESULT MoveNext(LONG lSkip, bool bForward)
- {
- HRESULT hr;
- ULONG ulRowsFetched = 0;
-
- // Check the data was opened successfully and the accessor
- // has been set.
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_pAccessor != NULL);
-
- // Release a row if one is already around
- ReleaseRows();
-
- // Get the row handle
- HROW* phRow = &m_hRow;
- hr = m_spRowset->GetNextRows(NULL, lSkip, (bForward) ? 1 : -1, &ulRowsFetched, &phRow);
- if (hr != S_OK)
- return hr;
-
- // Get the data
- hr = GetData();
- if (FAILED(hr))
- {
- ATLTRACE2(atlTraceDBClient, 0, _T("GetData failed - HRESULT = 0x%X\n"),hr);
- ReleaseRows();
- }
- return hr;
- }
- // Move to the first record
- HRESULT MoveFirst()
- {
- HRESULT hr;
-
- // Check the data was opened successfully and the accessor
- // has been set.
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_pAccessor != NULL);
-
- // Release a row if one is already around
- ReleaseRows();
-
- hr = m_spRowset->RestartPosition(NULL);
- if (FAILED(hr))
- return hr;
-
- // Get the data
- return MoveNext();
- }
- // Move to the last record
- HRESULT MoveLast()
- {
- // Check the data was opened successfully and the accessor
- // has been set.
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_pAccessor != NULL);
-
- // Release a row if one is already around
- ReleaseRows();
-
- HRESULT hr;
- ULONG ulRowsFetched = 0;
- HROW* phRow = &m_hRow;
- // Restart the rowset position and then move backwards
- m_spRowset->RestartPosition(NULL);
- hr = m_spRowset->GetNextRows(NULL, -1, 1, &ulRowsFetched, &phRow);
- if (hr != S_OK)
- return hr;
-
- // Get the data
- hr = GetData();
- if (FAILED(hr))
- {
- ATLTRACE2(atlTraceDBClient, 0, _T("GetData from MoveLast failed - HRESULT = 0x%X\n"),hr);
- ReleaseRows();
- }
-
- return S_OK;
- }
- // Move to the passed bookmark
- HRESULT MoveToBookmark(const CBookmarkBase& bookmark, LONG lSkip = 0)
- {
- // Check the data was opened successfully and the accessor
- // has been set.
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_pAccessor != NULL);
-
- CComPtr<IRowsetLocate> spLocate;
- HRESULT hr = m_spRowset.QueryInterface(&spLocate);
- if (FAILED(hr))
- return hr;
-
- // Release a row if one is already around
- ReleaseRows();
-
- ULONG ulRowsFetched = 0;
- HROW* phRow = &m_hRow;
- hr = spLocate->GetRowsAt(NULL, NULL, bookmark.GetSize(), bookmark.GetBuffer(),
- lSkip, 1, &ulRowsFetched, &phRow);
- // Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
- if (hr != S_OK)
- return hr;
-
- // Get the data
- hr = GetData();
- if (FAILED(hr))
- {
- ATLTRACE2(atlTraceDBClient, 0, _T("GetData from Bookmark failed - HRESULT = 0x%X\n"),hr);
- ReleaseRows();
- }
-
- return S_OK;
- }
- // Get the data for the current record
- HRESULT GetData()
- {
- HRESULT hr = S_OK;
- ATLASSERT(m_pAccessor != NULL);
-
- ULONG nAccessors = m_pAccessor->GetNumAccessors();
- for (ULONG i=0; i<nAccessors; i++)
- {
- if (m_pAccessor->IsAutoAccessor(i))
- {
- hr = GetData(i);
- if (FAILED(hr))
- return hr;
- }
- }
- return hr;
- }
- // Get the data for the passed accessor. Use for a non-auto accessor
- HRESULT GetData(int nAccessor)
- {
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_pAccessor != NULL);
- ATLASSERT(m_hRow != NULL);
-
- // Note that we are using the specified buffer if it has been set,
- // otherwise we use the accessor for the data.
- return m_spRowset->GetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor), m_pAccessor->GetBuffer());
- }
- // Get the data for the passed accessor. Use for a non-auto accessor
- HRESULT GetDataHere(int nAccessor, void* pBuffer)
- {
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_pAccessor != NULL);
- ATLASSERT(m_hRow != NULL);
-
- // Note that we are using the specified buffer if it has been set,
- // otherwise we use the accessor for the data.
- return m_spRowset->GetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor), pBuffer);
- }
- HRESULT GetDataHere(void* pBuffer)
- {
- HRESULT hr = S_OK;
-
- ULONG nAccessors = m_pAccessor->GetNumAccessors();
- for (ULONG i=0; i<nAccessors; i++)
- {
- hr = GetDataHere(i, pBuffer);
- if (FAILED(hr))
- return hr;
- }
- return hr;
- }
-
- // Insert the current record
- HRESULT Insert(int nAccessor = 0, bool bGetHRow = false)
- {
- ATLASSERT(m_pAccessor != NULL);
- HRESULT hr;
- if (m_spRowsetChange != NULL)
- {
- HROW* pHRow;
- if (bGetHRow)
- {
- ReleaseRows();
- pHRow = &m_hRow;
- }
- else
- pHRow = NULL;
-
- hr = m_spRowsetChange->InsertRow(NULL, m_pAccessor->GetHAccessor(nAccessor),
- m_pAccessor->GetBuffer(), pHRow);
-
- }
- else
- hr = E_NOINTERFACE;
-
- return hr;
- }
- // Delete the current record
- HRESULT Delete() const
- {
- ATLASSERT(m_pAccessor != NULL);
- HRESULT hr;
- if (m_spRowsetChange != NULL)
- hr = m_spRowsetChange->DeleteRows(NULL, 1, &m_hRow, NULL);
- else
- hr = E_NOINTERFACE;
-
- return hr;
- }
- // Update the current record
- HRESULT SetData() const
- {
- ATLASSERT(m_pAccessor != NULL);
- HRESULT hr = S_OK;
-
- ULONG nAccessors = m_pAccessor->GetNumAccessors();
- for (ULONG i=0; i<nAccessors; i++)
- {
- hr = SetData(i);
- if (FAILED(hr))
- return hr;
- }
- return hr;
- }
- // Update the current record with the data in the passed accessor
- HRESULT SetData(int nAccessor) const
- {
- ATLASSERT(m_pAccessor != NULL);
- HRESULT hr;
- if (m_spRowsetChange != NULL)
- {
- hr = m_spRowsetChange->SetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor),
- m_pAccessor->GetBuffer());
- }
- else
- hr = E_NOINTERFACE;
-
- return hr;
- }
-
- // Get the data most recently fetched from or transmitted to the data source.
- // Does not get values based on pending changes.
- HRESULT GetOriginalData()
- {
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_pAccessor != NULL);
-
- HRESULT hr = S_OK;
- CComPtr<IRowsetUpdate> spRowsetUpdate;
- hr = m_spRowset->QueryInterface(&spRowsetUpdate);
- if (FAILED(hr))
- return hr;
-
- ULONG nAccessors = m_pAccessor->GetNumAccessors();
- for (ULONG i = 0; i < nAccessors; i++)
- {
- hr = spRowsetUpdate->GetOriginalData(m_hRow, m_pAccessor->GetHAccessor(i), m_pAccessor->GetBuffer());
- if (FAILED(hr))
- return hr;
- }
- return hr;
- }
- // Get the status of the current row
- HRESULT GetRowStatus(DBPENDINGSTATUS* pStatus) const
- {
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(pStatus != NULL);
-
- CComPtr<IRowsetUpdate> spRowsetUpdate;
- HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
- if (FAILED(hr))
- return hr;
-
- return spRowsetUpdate->GetRowStatus(NULL, 1, &m_hRow, pStatus);
- }
- // Undo any changes made to the current row since it was last fetched or Update
- // was called for it
- HRESULT Undo(ULONG* pcRows = NULL, HROW* phRow = NULL, DBROWSTATUS* pStatus = NULL)
- {
- ATLASSERT(m_spRowset != NULL);
-
- CComPtr<IRowsetUpdate> spRowsetUpdate;
- HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
- if (FAILED(hr))
- return hr;
-
- HROW* prgRows;
- DBROWSTATUS* pRowStatus;
- if (phRow != NULL)
- hr = spRowsetUpdate->Undo(NULL, 1, &m_hRow, pcRows, &prgRows, &pRowStatus);
- else
- hr = spRowsetUpdate->Undo(NULL, 1, &m_hRow, pcRows, NULL, &pRowStatus);
- if (FAILED(hr))
- return hr;
-
- if (phRow != NULL)
- {
- *phRow = *prgRows;
- CoTaskMemFree(prgRows);
- }
- if (pStatus != NULL)
- *pStatus = *pRowStatus;
-
- CoTaskMemFree(pRowStatus);
- return hr;
- }
- // Transmits any pending changes made to a row since it was last fetched or Update was
- // called for it. Also see SetData.
- HRESULT Update(ULONG* pcRows = NULL, HROW* phRow = NULL, DBROWSTATUS* pStatus = NULL)
- {
- ATLASSERT(m_spRowset != NULL);
-
- CComPtr<IRowsetUpdate> spRowsetUpdate;
- HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
- if (FAILED(hr))
- return hr;
-
- HROW* prgRows;
- DBROWSTATUS* pRowStatus;
- if (phRow != NULL)
- hr = spRowsetUpdate->Update(NULL, 1, &m_hRow, pcRows, &prgRows, &pRowStatus);
- else
- hr = spRowsetUpdate->Update(NULL, 1, &m_hRow, pcRows, NULL, &pRowStatus);
- if (FAILED(hr))
- return hr;
-
- if (phRow != NULL)
- {
- *phRow = *prgRows;
- CoTaskMemFree(prgRows);
- }
- if (pStatus != NULL)
- *pStatus = *pRowStatus;
-
- CoTaskMemFree(pRowStatus);
- return hr;
- }
-
- // Get the approximate position of the row corresponding to the passed bookmark
- HRESULT GetApproximatePosition(const CBookmarkBase* pBookmark, ULONG* pPosition, ULONG* pcRows)
- {
- ATLASSERT(m_spRowset != NULL);
-
- CComPtr<IRowsetScroll> spRowsetScroll;
- HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
- if (SUCCEEDED(hr))
- {
- if (pBookmark != NULL)
- hr = spRowsetScroll->GetApproximatePosition(NULL, pBookmark->GetSize(), pBookmark->GetBuffer(),
- pPosition, pcRows);
- else
- hr = spRowsetScroll->GetApproximatePosition(NULL, 0, NULL, pPosition, pcRows);
-
- }
- return hr;
-
- }
- // Move to a fractional position in the rowset
- HRESULT MoveToRatio(ULONG nNumerator, ULONG nDenominator, bool bForward = true)
- {
- ATLASSERT(m_spRowset != NULL);
- ULONG nRowsFetched;
-
- CComPtr<IRowsetScroll> spRowsetScroll;
- HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
- if (FAILED(hr))
- return hr;
-
- ReleaseRows();
- HROW* phRow = &m_hRow;
- hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, (bForward) ? 1 : -1,
- &nRowsFetched, &phRow);
- // Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
- if (hr == S_OK)
- hr = GetData();
-
- return hr;
- }
-
- // Implementation
- static const IID& GetIID()
- {
- return IID_IRowset;
- }
- IRowset* GetInterface() const
- {
- return m_spRowset;
- }
- IRowset** GetInterfacePtr()
- {
- return &m_spRowset;
- }
- void SetupOptionalRowsetInterfaces()
- {
- // Cache IRowsetChange if available
- if (m_spRowset != NULL)
- m_spRowset->QueryInterface(&m_spRowsetChange);
- }
- HRESULT BindFinished() const { return S_OK; }
- void SetAccessor(CAccessorBase* pAccessor)
- {
- m_pAccessor = pAccessor;
- }
-
- CComPtr<IRowset> m_spRowset;
- CComPtr<IRowsetChange> m_spRowsetChange;
- CAccessorBase* m_pAccessor;
- HROW m_hRow;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CBulkRowset
-
- class CBulkRowset : public CRowset
- {
- public:
- CBulkRowset()
- {
- // Default the number of rows to bulk fetch to 10
- m_nRows = 10;
- m_hr = S_OK;
- m_phRow = NULL;
- }
- CBulkRowset::~CBulkRowset()
- {
- Close();
-
- delete [] m_phRow;
- }
- // Set the number of row handles that will be retrieved in each
- // bulk row fetch. The default is 10 and this function must be called
- // before Open if you wish to change it.
- void SetRows(ULONG nRows)
- {
- // This function must be called before the memory is allocated
- // during binding
- ATLASSERT(m_phRow == NULL);
- m_nRows = nRows;
- }
- // AddRef all the currently retrieved row handles
- HRESULT AddRefRows()
- {
- ATLASSERT(m_spRowset != NULL);
- return m_spRowset->AddRefRows(m_nCurrentRows, m_phRow, NULL, NULL);
- }
- // Release all the currently retrieved row handles
- HRESULT ReleaseRows()
- {
- ATLASSERT(m_spRowset != NULL);
- // We're going to Release the rows so reset the current row position
- m_nCurrentRow = 0;
- m_hRow = NULL;
- return m_spRowset->ReleaseRows(m_nCurrentRows, m_phRow, NULL, NULL, NULL);
- }
- // Move to the first record
- HRESULT MoveFirst()
- {
- ATLASSERT(m_spRowset != NULL);
- ReleaseRows();
-
- // Cause MoveNext to perform a new bulk fetch
- m_nCurrentRow = m_nRows;
-
- HRESULT hr = m_spRowset->RestartPosition(NULL);
- if (FAILED(hr))
- return hr;
-
- // Get the data
- return MoveNext();
- }
- // Move to the next record
- HRESULT MoveNext()
- {
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_phRow != NULL);
-
- // Move to the next record in the buffer
- m_nCurrentRow++;
-
- // Have we reached the end of the buffer?
- if (m_nCurrentRow >= m_nCurrentRows)
- {
- // If we've reached the end of the buffer and we had a non S_OK HRESULT from
- // the last call to GetNextRows then return that HRESULT now.
- if (m_hr != S_OK)
- return m_hr;
-
- // We've finished with these rows so we need some more
- // First release any HROWs that we have
- ReleaseRows();
-
- m_hr = m_spRowset->GetNextRows(NULL, 0, m_nRows, &m_nCurrentRows, &m_phRow);
- // If we have an error HRESULT or we haven't retrieved any rows then return
- // the HRESULT now.
- if (FAILED(m_hr) || m_nCurrentRows == 0)
- return m_hr;
- }
-
- // Get the data for the current row
- m_hRow = m_phRow[m_nCurrentRow];
- return GetData();
- }
- // Move to the previous record
- HRESULT MovePrev()
- {
- ATLASSERT(m_spRowset != NULL);
- ATLASSERT(m_phRow != NULL);
-
- // Check if we're at the start of the block
- if (m_nCurrentRow == 0)
- {
- ReleaseRows();
-
- // Go back the amount of rows in the block - 1 and fetch forward
- m_hr = m_spRowset->GetNextRows(NULL, -(LONG)m_nRows-1, m_nRows, &m_nCurrentRows, &m_phRow);
-
- // Set the current record to the end of the new block
- m_nCurrentRow = m_nCurrentRows - 1;
-
- // If we have an error HRESULT or we haven't retrieved any rows then return
- // the HRESULT now.
- if (FAILED(m_hr) || m_nCurrentRows == 0)
- return m_hr;
- }
- else
- {
- // Move back a row in the block
- m_nCurrentRow--;
- }
-
- // Get the data for the current row
- m_hRow = m_phRow[m_nCurrentRow];
- return GetData();
- }
- // Move to the last record
- HRESULT MoveLast()
- {
- ReleaseRows();
- return CRowset::MoveLast();
- }
- // Move to the passed bookmark
- HRESULT MoveToBookmark(const CBookmarkBase& bookmark, LONG lSkip = 0)
- {
- ATLASSERT(m_spRowset != NULL);
- CComPtr<IRowsetLocate> spLocate;
- HRESULT hr = m_spRowset->QueryInterface(&spLocate);
- if (FAILED(hr))
- return hr;
-
- ReleaseRows();
- m_hr = spLocate->GetRowsAt(NULL, NULL, bookmark.GetSize(), bookmark.GetBuffer(),
- lSkip, m_nRows, &m_nCurrentRows, &m_phRow);
- if (m_hr != S_OK || m_nCurrentRows == 0)
- return m_hr;
-
- // Get the data
- m_hRow = m_phRow[m_nCurrentRow];
- return GetData();
- }
- // Move to a fractional position in the rowset
- HRESULT MoveToRatio(ULONG nNumerator, ULONG nDenominator)
- {
- ATLASSERT(m_spRowset != NULL);
-
- CComPtr<IRowsetScroll> spRowsetScroll;
- HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
- if (FAILED(hr))
- return hr;
-
- ReleaseRows();
- m_hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, m_nRows, &m_nCurrentRows, &m_phRow);
- if (m_hr != S_OK || m_nCurrentRows == 0)
- return m_hr;
-
- // Get the data
- m_hRow = m_phRow[m_nCurrentRow];
- return GetData();
- }
- // Insert the current record
- HRESULT Insert(int nAccessor = 0, bool bGetHRow = false)
- {
- ReleaseRows();
- return CRowset::Insert(nAccessor, bGetHRow);
- }
-
- // Implementation
- HRESULT BindFinished()
- {
- // No rows in the buffer yet
- m_nCurrentRows = 0;
- // Cause MoveNext to automatically perform a new bulk fetch the first time
- m_nCurrentRow = m_nRows;
-
- m_phRow = NULL;
- ATLTRY(m_phRow = new HROW[m_nRows]);
- if (m_phRow == NULL)
- return E_OUTOFMEMORY;
-
- return S_OK;
- }
-
- HRESULT m_hr; // HRESULT to return from MoveNext at end of buffer
- HROW* m_phRow; // Pointer to array of HROWs for each row in buffer
- ULONG m_nRows; // Number of rows that will fit in the buffer
- ULONG m_nCurrentRows; // Number of rows currently in the buffer
- ULONG m_nCurrentRow;
- };
-
- ///////////////////////////////////////////////////////////////////////////
- // class CArrayRowset
- //
- // Allows you to access a rowset with an array syntax
-
- template <class T, class TRowset = CRowset>
- class CArrayRowset :
- public CVirtualBuffer<T>,
- public TRowset
- {
- public:
- CArrayRowset(int nMax = 100000) : CVirtualBuffer<T>(nMax)
- {
- m_nRowsRead = 0;
- }
- T& operator[](int nRow)
- {
- ATLASSERT(nRow >= 0);
- HRESULT hr;
- T* m_pCurrent = m_pBase + m_nRowsRead;
-
- // Retrieve the row if we haven't retrieved it already
- while ((ULONG)nRow >= m_nRowsRead)
- {
- m_pAccessor->SetBuffer((BYTE*)m_pCurrent);
- __try
- {
- // Get the row
- hr = MoveNext();
- if (hr != S_OK)
- {
- *((char*)0) = 0; // Force exception
- }
- }
- __except(Except(GetExceptionInformation()))
- {
- }
- m_nRowsRead++;
- m_pCurrent++;
- }
-
- return *(m_pBase + nRow);
- }
-
- HRESULT Snapshot()
- {
- ATLASSERT(m_nRowsRead == 0);
- ATLASSERT(m_spRowset != NULL);
- HRESULT hr = MoveFirst();
- if (FAILED(hr))
- return hr;
- do
- {
- Write(*(T*)m_pAccessor->GetBuffer());
- m_nRowsRead++;
- hr = MoveNext();
- } while (SUCCEEDED(hr) && hr != DB_S_ENDOFROWSET);
-
- return (hr == DB_S_ENDOFROWSET) ? S_OK : hr;
- }
-
-
- // Implementation
- ULONG m_nRowsRead;
- };
-
- // Used when you don't need any parameters or output columns
- class CNoAccessor
- {
- public:
- // We don't need any typedef's here as the default
- // global typedef is not to have any parameters and
- // output columns.
- HRESULT BindColumns(IUnknown*) { return S_OK; }
- HRESULT BindParameters(HACCESSOR*, ICommand*, void**) { return S_OK; }
- void Close() { }
- HRESULT ReleaseAccessors(IUnknown*) { return S_OK; }
- };
-
- // Used when a rowset will not be returned from the command
- class CNoRowset
- {
- public:
- HRESULT BindFinished() { return S_OK; }
- void Close() { }
- static const IID& GetIID() { return IID_NULL; }
- IRowset* GetInterface() const { return NULL; }
- IRowset** GetInterfacePtr() { return NULL; }
- void SetAccessor(void*) { }
- void SetupOptionalRowsetInterfaces() { }
- };
-
- ///////////////////////////////////////////////////////////////////////////
- // class CAccessor
-
- // T is the class that contains the data that will be accessed.
- template <class T>
- class CAccessor :
- public T,
- public CAccessorBase
- {
- public:
- // Implementation
- // Free's any columns in the current record that need to be freed.
- // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
- void FreeRecordMemory(IRowset* /* pRowset */)
- {
- ULONG nColumns;
- ULONG i;
-
- for (i = 0; i < GetNumAccessors(); i++)
- {
- // Passing in m_pBuffer tells the column entry maps to free the
- // memory for the types if appropriate
- _GetBindEntries(&nColumns, NULL, i, NULL, m_pBuffer);
- }
- }
- HRESULT BindColumns(IUnknown* pUnk)
- {
- HRESULT hr;
- ULONG nAccessors;
- ULONG nSize;
- nAccessors = _OutputColumnsClass::_GetNumAccessors();
-
- SetBuffer((BYTE*)this);
-
- nSize = sizeof(T);
- hr = BindAccessors(nAccessors, nSize, pUnk);
- return hr;
- }
- HRESULT BindAccessors(ULONG nAccessors, ULONG nSize, IUnknown* pUnk)
- {
- ATLASSERT(pUnk != NULL);
- HRESULT hr;
-
- CComPtr<IAccessor> spAccessor;
- hr = pUnk->QueryInterface(&spAccessor);
- if (SUCCEEDED(hr))
- {
- // Allocate the accessor memory if we haven't done so yet
- if (m_pAccessorInfo == NULL)
- {
- hr = AllocateAccessorMemory(nAccessors);
- if (FAILED(hr))
- return hr;
- }
-
- for (ULONG i=0; i<nAccessors && SUCCEEDED(hr); i++)
- hr = BindAccessor(spAccessor, i, nSize);
- }
-
- return hr;
- }
-
- HRESULT BindAccessor(IAccessor* pAccessor, ULONG nAccessor, ULONG nSize)
- {
- DBBINDING* pBindings = NULL;
- ULONG nColumns;
- bool bAuto;
- HRESULT hr;
-
- // First time just get the number of entries by passing in &nColumns
- _OutputColumnsClass::_GetBindEntries(&nColumns, NULL, nAccessor, NULL);
-
- // Now allocate the binding structures
- ATLTRY(pBindings = new DBBINDING[nColumns]);
- if (pBindings == NULL)
- return E_OUTOFMEMORY;
-
- // Now get the bind entries
- hr = _OutputColumnsClass::_GetBindEntries(&nColumns, pBindings, nAccessor, &bAuto);
- if (FAILED(hr))
- return hr;
-
- m_pAccessorInfo[nAccessor].bAutoAccessor = bAuto;
- hr = BindEntries(pBindings, nColumns, &m_pAccessorInfo[nAccessor].hAccessor, nSize, pAccessor);
- delete [] pBindings;
- return hr;
- }
-
- HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer)
- {
- HRESULT hr = S_OK;
- // In the static accessor case, the parameter buffer will be T
- *ppParameterBuffer = this;
-
- // Only bind the parameters if we haven't already done it
- if (*pHAccessor == NULL)
- {
- ULONG nColumns;
- _ParamClass::_GetParamEntries(&nColumns, NULL);
-
- DBBINDING* pBinding = NULL;
- ATLTRY(pBinding = new DBBINDING[nColumns]);
- if (pBinding == NULL)
- return E_OUTOFMEMORY;
-
- hr = _ParamClass::_GetParamEntries(&nColumns, pBinding);
- if (SUCCEEDED(hr))
- {
- // Get the IAccessor from the passed IUnknown
- CComPtr<IAccessor> spAccessor;
- hr = pCommand->QueryInterface(&spAccessor);
- if (SUCCEEDED(hr))
- {
- hr = BindEntries(pBinding, nColumns, pHAccessor, sizeof(T),
- spAccessor);
- }
- }
- delete [] pBinding;
- }
- return hr;
- }
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // CDynamicAccessor
-
- class CDynamicAccessor :
- public CAccessorBase
- {
- public:
- CDynamicAccessor()
- {
- m_nColumns = 0;
- m_pColumnInfo = NULL;
- m_pStringsBuffer = NULL;
- };
- ~CDynamicAccessor()
- {
- Close();
- }
- void Close()
- {
- if (m_pColumnInfo != NULL)
- {
- CoTaskMemFree(m_pColumnInfo);
- m_pColumnInfo = NULL;
- }
-
- // Free the memory for the string buffer returned by IColumnsInfo::GetColumnInfo,
- // if necessary
- if (m_pStringsBuffer != NULL)
- {
- CoTaskMemFree(m_pStringsBuffer);
- m_pStringsBuffer = NULL;
- }
-
- delete [] m_pBuffer;
- m_pBuffer = NULL;
- m_nColumns = 0;
-
- CAccessorBase::Close();
- }
- bool GetColumnType(ULONG nColumn, DBTYPE* pType) const
- {
- if (TranslateColumnNo(nColumn))
- {
- *pType = m_pColumnInfo[nColumn].wType;
- return true;
- }
- else
- return false;
- }
- bool GetColumnFlags(ULONG nColumn, DBCOLUMNFLAGS* pFlags) const
- {
- if (TranslateColumnNo(nColumn))
- {
- *pFlags = m_pColumnInfo[nColumn].dwFlags;
- return true;
- }
- else
- return false;
- }
- bool GetOrdinal(TCHAR* pColumnName, ULONG* pOrdinal) const
- {
- ATLASSERT(pColumnName != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- {
- *pOrdinal = m_pColumnInfo[nColumn].iOrdinal;
- return true;
- }
- else
- return false;
- }
-
- void* GetValue(ULONG nColumn) const
- {
- if (TranslateColumnNo(nColumn))
- return _GetDataPtr(nColumn);
- else
- return NULL;
- }
-
- void* GetValue(TCHAR* pColumnName) const
- {
- ATLASSERT(pColumnName != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- return _GetDataPtr(nColumn);
- else
- return NULL; // Not Found
- }
-
- template <class ctype>
- void _GetValue(ULONG nColumn, ctype* pData) const
- {
- ATLASSERT(pData != NULL);
- ATLASSERT(m_pColumnInfo[nColumn].ulColumnSize == sizeof(ctype));
- ctype* pBuffer = (ctype*)_GetDataPtr(nColumn);
- *pData = *pBuffer;
- }
- template <class ctype>
- void _SetValue(ULONG nColumn, const ctype& data)
- {
- ATLASSERT(m_pColumnInfo[nColumn].ulColumnSize == sizeof(ctype));
- ctype* pBuffer = (ctype*)_GetDataPtr(nColumn);
- *pBuffer = (ctype)data;
- }
- template <class ctype>
- bool GetValue(ULONG nColumn, ctype* pData) const
- {
- if (TranslateColumnNo(nColumn))
- {
- _GetValue(nColumn, pData);
- return true;
- }
- return false;
- }
- template <class ctype>
- bool SetValue(ULONG nColumn, const ctype& data)
- {
- if (TranslateColumnNo(nColumn))
- {
- _SetValue(nColumn, data);
- return true;
- }
- return false;
- }
- template <class ctype>
- bool GetValue(TCHAR *pColumnName, ctype* pData) const
- {
- ATLASSERT(pColumnName != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- {
- _GetValue(nColumn, pData);
- return true;
- }
- return false;
- }
- template <class ctype>
- bool SetValue(TCHAR *pColumnName, const ctype& data)
- {
- ATLASSERT(pColumnName != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- {
- _SetValue(nColumn, data);
- return true;
- }
- return false;
- }
- bool GetLength(ULONG nColumn, ULONG* pLength) const
- {
- ATLASSERT(pLength != NULL);
- if (TranslateColumnNo(nColumn))
- {
- *pLength = *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize));
- return true;
- }
- else
- return false;
- }
- bool SetLength(ULONG nColumn, ULONG nLength)
- {
- if (TranslateColumnNo(nColumn))
- {
- *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize)) = nLength;
- return true;
- }
- else
- return false;
- }
- bool GetLength(TCHAR* pColumnName, ULONG* pLength) const
- {
- ATLASSERT(pColumnName != NULL);
- ATLASSERT(pLength != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- {
- *pLength = *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize));
- return true;
- }
- else
- return false;
- }
- bool SetLength(TCHAR* pColumnName, ULONG nLength)
- {
- ATLASSERT(pColumnName != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- {
- *(ULONG*)(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize)) = nLength;
- return true;
- }
- else
- return false;
- }
- bool GetStatus(ULONG nColumn, DBSTATUS* pStatus) const
- {
- ATLASSERT(pStatus != NULL);
- if (TranslateColumnNo(nColumn))
- {
- *pStatus = *(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG)));
- return true;
- }
- else
- return false;
- }
- bool SetStatus(ULONG nColumn, DBSTATUS status)
- {
- if (TranslateColumnNo(nColumn))
- {
- *(ULONG*)(AddOffset(AddOffset((ULONG)_GetDataPtr(nColumn), m_pColumnInfo[nColumn].ulColumnSize), sizeof(ULONG))) = status;
- return true;
- }
- else
- return false;
- }
- bool GetStatus(TCHAR* pColumnName, DBSTATUS* pStatus) const
- {
- ATLASSERT(pColumnName != NULL);
- ATLASSERT(pStatus != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- {
- *pStatus = *(ULONG*)((BYTE*)_GetDataPtr(nColumn) + m_pColumnInfo[nColumn].ulColumnSize + sizeof(ULONG));
- return true;
- }
- else
- return false;
- }
- bool SetStatus(TCHAR* pColumnName, DBSTATUS status)
- {
- ATLASSERT(pColumnName != NULL);
- ULONG nColumn;
- if (GetInternalColumnNo(pColumnName, &nColumn))
- {
- *(ULONG*)((BYTE*)_GetDataPtr(nColumn) + m_pColumnInfo[nColumn].ulColumnSize + sizeof(ULONG)) = status;
- return true;
- }
- else
- return false;
- }
-
- // Returns true if a bookmark is available
- HRESULT GetBookmark(CBookmark<>* pBookmark) const
- {
- HRESULT hr;
- if (m_pColumnInfo->iOrdinal == 0)
- hr = pBookmark->SetBookmark(m_pColumnInfo->ulColumnSize, (BYTE*)_GetDataPtr(0));
- else
- hr = E_FAIL;
- return hr;
- }
-
- ULONG GetColumnCount() const
- {
- return m_nColumns;
- }
-
- LPOLESTR GetColumnName(ULONG nColumn) const
- {
- if (TranslateColumnNo(nColumn))
- return m_pColumnInfo[nColumn].pwszName;
- else
- return NULL;
- }
-
- HRESULT GetColumnInfo(IRowset* pRowset, ULONG* pColumns, DBCOLUMNINFO** ppColumnInfo)
- {
- CComPtr<IColumnsInfo> spColumnsInfo;
- HRESULT hr = pRowset->QueryInterface(&spColumnsInfo);
- if (SUCCEEDED(hr))
- hr = spColumnsInfo->GetColumnInfo(pColumns, ppColumnInfo, &m_pStringsBuffer);
-
- return hr;
- }
-
- HRESULT AddBindEntry(const DBCOLUMNINFO& info)
- {
- m_pColumnInfo = (DBCOLUMNINFO*)CoTaskMemRealloc(m_pColumnInfo, (m_nColumns + 1) * sizeof(DBCOLUMNINFO));
- if (m_pColumnInfo == NULL)
- return E_OUTOFMEMORY;
-
- m_pColumnInfo[m_nColumns] = info;
- m_nColumns++;
-
- return S_OK;
- }
-
- // Implementation
- // Free's any columns in the current record that need to be freed.
- // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
- void FreeRecordMemory(IRowset* pRowset)
- {
- ULONG i;
-
- for (i = 0; i < m_nColumns; i++)
- CAccessorBase::FreeType(m_pColumnInfo[i].wType, (BYTE*)_GetDataPtr(i), pRowset);
- }
- void* _GetDataPtr(ULONG nColumn) const
- {
- return m_pBuffer + (ULONG)m_pColumnInfo[nColumn].pTypeInfo;
- }
- bool GetInternalColumnNo(TCHAR* pColumnName, ULONG* pColumn) const
- {
- ATLASSERT(pColumnName != NULL);
- ATLASSERT(pColumn != NULL);
- USES_CONVERSION;
- ULONG i;
- ULONG nSize = (lstrlen(pColumnName) + 1) * sizeof(OLECHAR);
- OLECHAR* pOleColumnName = T2OLE(pColumnName);
-
- // Search through the columns trying to find a match
- for (i = 0; i < m_nColumns; i++)
- {
- if (m_pColumnInfo[i].pwszName != NULL &&
- memcmp(m_pColumnInfo[i].pwszName, pOleColumnName, nSize) == 0)
- break;
- }
- if (i < m_nColumns)
- {
- *pColumn = i;
- return true;
- }
- else
- return false; // Not Found
- }
- HRESULT BindColumns(IUnknown* pUnk)
- {
- ATLASSERT(pUnk != NULL);
- CComPtr<IAccessor> spAccessor;
- HRESULT hr = pUnk->QueryInterface(&spAccessor);
- if (FAILED(hr))
- return hr;
-
- ULONG i;
- ULONG nOffset = 0, nLengthOffset, nStatusOffset;
-
- // If the user hasn't specifed the column information to bind by calling AddBindEntry then
- // we get it ourselves
- if (m_pColumnInfo == NULL)
- {
- CComPtr<IColumnsInfo> spColumnsInfo;
- hr = pUnk->QueryInterface(&spColumnsInfo);
- if (FAILED(hr))
- return hr;
-
- hr = spColumnsInfo->GetColumnInfo(&m_nColumns, &m_pColumnInfo, &m_pStringsBuffer);
- if (FAILED(hr))
- return hr;
-
- m_bOverride = false;
- }
- else
- m_bOverride = true;
-
- DBBINDING* pBinding = NULL;
- ATLTRY(pBinding= new DBBINDING[m_nColumns]);
- if (pBinding == NULL)
- return E_OUTOFMEMORY;
-
- DBBINDING* pCurrent = pBinding;
- DBOBJECT* pObject;
- for (i = 0; i < m_nColumns; i++)
- {
- // If it's a BLOB or the column size is large enough for us to treat it as
- // a BLOB then we also need to set up the DBOBJECT structure.
- if (m_pColumnInfo[i].ulColumnSize > 1024 || m_pColumnInfo[i].wType == DBTYPE_IUNKNOWN)
- {
- pObject = NULL;
- ATLTRY(pObject = new DBOBJECT);
- if (pObject == NULL)
- return E_OUTOFMEMORY;
- pObject->dwFlags = STGM_READ;
- pObject->iid = IID_ISequentialStream;
- m_pColumnInfo[i].wType = DBTYPE_IUNKNOWN;
- m_pColumnInfo[i].ulColumnSize = sizeof(IUnknown*);
- }
- else
- pObject = NULL;
-
- // If column is of type STR or WSTR increase length by 1
- // to accommodate the NULL terminator.
- if (m_pColumnInfo[i].wType == DBTYPE_STR ||
- m_pColumnInfo[i].wType == DBTYPE_WSTR)
- m_pColumnInfo[i].ulColumnSize += 1;
-
- nLengthOffset = AddOffset(nOffset, m_pColumnInfo[i].ulColumnSize);
- nStatusOffset = AddOffset(nLengthOffset, sizeof(ULONG));
- Bind(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
- m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
- DBPARAMIO_NOTPARAM, nOffset,
- nLengthOffset, nStatusOffset, pObject);
- pCurrent++;
-
- // Note that, as we're not using this for anything else, we're using the
- // pTypeInfo element to store the offset to our data.
- m_pColumnInfo[i].pTypeInfo = (ITypeInfo*)nOffset;
-
- nOffset = AddOffset(nStatusOffset, sizeof(DBSTATUS));
- }
- // Allocate the accessor memory if we haven't done so yet
- if (m_pAccessorInfo == NULL)
- {
- hr = AllocateAccessorMemory(1); // We only have one accessor
- if (FAILED(hr))
- {
- delete [] pBinding;
- return hr;
- }
- m_pAccessorInfo->bAutoAccessor = TRUE;
- }
-
- // Allocate enough memory for the data buffer and tell the rowset
- // Note that the rowset will free the memory in its destructor.
- m_pBuffer = NULL;
- ATLTRY(m_pBuffer = new BYTE[nOffset]);
- if (m_pBuffer == NULL)
- {
- delete [] pBinding;
- return E_OUTOFMEMORY;
- }
- hr = BindEntries(pBinding, m_nColumns, &m_pAccessorInfo->hAccessor,
- nOffset, spAccessor);
- delete [] pBinding;
-
- return hr;
- }
-
- static ULONG AddOffset(ULONG nCurrent, ULONG nAdd)
- {
- struct foobar
- {
- char foo;
- long bar;
- };
- ULONG nAlign = offsetof(foobar, bar);
-
- return nCurrent + nAdd + (nAdd % nAlign);;
- }
-
- // Translate the column number to the index into the column info array
- bool TranslateColumnNo(ULONG& nColumn) const
- {
- ATLASSERT(m_pColumnInfo != NULL);
- // If the user has overriden the binding then we need to search
- // through the column info for the ordinal number
- if (m_bOverride)
- {
- for (ULONG i = 0; i < m_nColumns; i++)
- {
- if (m_pColumnInfo[i].iOrdinal == nColumn)
- {
- nColumn = i;
- return true;
- }
- }
- return false;
- }
- else
- {
- // Note that m_pColumnInfo->iOrdinal will be zero if have bound
- // a bookmark as the first entry, otherwise it will be 1.
- // If the column is out of range then return false
- if (nColumn > (m_nColumns - 1 + m_pColumnInfo->iOrdinal))
- return false;
-
- // otherwise translate the column to an index into our internal
- // binding entries array
- nColumn -= m_pColumnInfo->iOrdinal;
- return true;
- }
- }
- typedef CDynamicAccessor _OutputColumnsClass;
- static bool HasOutputColumns() { return true; }
-
- ULONG m_nColumns;
- DBCOLUMNINFO* m_pColumnInfo;
- OLECHAR* m_pStringsBuffer;
- bool m_bOverride;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CDynamicParameterAccessor
-
- class CDynamicParameterAccessor : public CDynamicAccessor
- {
- // Constructors and Destructors
- public:
- typedef CDynamicParameterAccessor _ParamClass;
- CDynamicParameterAccessor()
- {
- m_pParameterEntry = NULL;
- m_pParameterBuffer = NULL;
- m_ppParamName = NULL;
- m_nParameterBufferSize = 0;
- m_nParams = 0;
- };
-
- ~CDynamicParameterAccessor()
- {
- delete [] m_pParameterEntry;
- if (m_ppParamName != NULL)
- {
- if (*m_ppParamName != NULL)
- CoTaskMemFree(*m_ppParamName);
- delete [] m_ppParamName;
- }
- delete m_pParameterBuffer;
- };
- // nParam is the parameter number (offset from 1)
- bool GetParamType(ULONG nParam, DBTYPE* pType) const
- {
- ATLASSERT(pType != NULL);
- if (nParam == 0 || nParam > m_nParams)
- return false;
-
- *pType = m_pParameterEntry[nParam-1].wType;
- return true;
- }
- template <class ctype>
- bool GetParam(ULONG nParam, ctype* pData) const
- {
- ATLASSERT(pData != NULL);
- ctype* pBuffer = (ctype*)GetParam(nParam);
- if (pBuffer == NULL)
- return false;
- *pData = *pBuffer;
- return true;
-
- }
- template <class ctype>
- bool SetParam(ULONG nParam, ctype* pData)
- {
- ATLASSERT(pData != NULL);
- ctype* pBuffer = (ctype*)GetParam(nParam);
- if (pBuffer == NULL)
- return false;
- *pBuffer = *pData;
- return true;
-
- }
- template <class ctype>
- bool GetParam(TCHAR* pParamName, ctype* pData) const
- {
- ATLASSERT(pData != NULL);
- ctype* pBuffer = (ctype*)GetParam(pParamName);
- if (pBuffer == NULL)
- return false;
- *pData = *pBuffer;
- return true;
-
- }
- template <class ctype>
- bool SetParam(TCHAR* pParamName, ctype* pData)
- {
- ATLASSERT(pData != NULL);
- ctype* pBuffer = (ctype*)GetParam(pParamName);
- if (pBuffer == NULL)
- return false;
- *pBuffer = *pData;
- return true;
-
- }
- void* GetParam(ULONG nParam) const
- {
- if (nParam == 0 || nParam > m_nParams)
- return NULL;
- else
- return m_pParameterBuffer + m_pParameterEntry[nParam-1].obValue;
- }
- void* GetParam(TCHAR* pParamName) const
- {
- USES_CONVERSION;
- ULONG i;
- ULONG nSize = (lstrlen(pParamName) + 1) * sizeof(OLECHAR);
- OLECHAR* pOleParamName = T2OLE(pParamName);
-
- for (i=0; i<m_nParams; i++)
- {
- if (memcmp(m_ppParamName[i], pOleParamName, nSize) == 0)
- break;
- }
- if (i < m_nParams)
- return (m_pParameterBuffer + m_pParameterEntry[i].obValue);
- else
- return NULL; // Not Found
- }
- // Get the number of parameters
- ULONG GetParamCount() const
- {
- return m_nParams;
- }
- // Get the parameter name for the passed parameter number
- LPOLESTR GetParamName(ULONG ulParam) const
- {
- ATLASSERT((ulParam >= 0) && (ulParam<m_nParams));
- return m_ppParamName[ulParam];
- }
-
- // Implementation
- HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand,
- void** ppParameterBuffer)
- {
- // If we have already bound the parameters then just return
- // the pointer to the parameter buffer
- if (*pHAccessor != NULL)
- {
- *ppParameterBuffer = m_pParameterBuffer;
- return S_OK;
- }
-
- CComPtr<IAccessor> spAccessor;
- HRESULT hr = pCommand->QueryInterface(&spAccessor);
- if (FAILED(hr))
- return hr;
-
- // Try to bind parameters if available
- CComPtr<ICommandWithParameters> spCommandParameters;
- hr = pCommand->QueryInterface(&spCommandParameters);
- if (FAILED(hr))
- return hr;
-
- ULONG ulParams = 0;
- DBPARAMINFO* pParamInfo = NULL;
- LPOLESTR pNamesBuffer = NULL;
-
- // Get Parameter Information
- hr = spCommandParameters->GetParameterInfo(&ulParams, &pParamInfo,
- &pNamesBuffer);
- if (FAILED(hr))
- return hr;
-
- // Create the parameter information for binding
- hr = AllocateParameterInfo(ulParams);
- if (FAILED(hr))
- {
- CoTaskMemFree(pParamInfo);
- CoTaskMemFree(pNamesBuffer);
- return hr;
- }
-
- ULONG nOffset = 0;
- DBBINDING* pCurrent = m_pParameterEntry;
- for (ULONG l=0; l<ulParams; l++)
- {
- m_pParameterEntry[l].eParamIO = 0;
- if (pParamInfo[l].dwFlags & DBPARAMFLAGS_ISINPUT)
- m_pParameterEntry[l].eParamIO |= DBPARAMIO_INPUT;
-
- if (pParamInfo[l].dwFlags & DBPARAMFLAGS_ISOUTPUT)
- m_pParameterEntry[l].eParamIO |= DBPARAMIO_OUTPUT;
-
- Bind(pCurrent, pParamInfo[l].iOrdinal, pParamInfo[l].wType,
- pParamInfo[l].ulParamSize, pParamInfo[l].bPrecision, pParamInfo[l].bScale,
- m_pParameterEntry[l].eParamIO, nOffset);
- pCurrent++;
-
- m_ppParamName[l] = pNamesBuffer;
- if (pNamesBuffer && *pNamesBuffer)
- {
- // Search for the NULL termination character
- while (*pNamesBuffer++)
- ;
- }
- nOffset += pParamInfo[l].ulParamSize;
-
- }
-
- // Allocate memory for the new buffer
- m_pParameterBuffer = NULL;
- ATLTRY(m_pParameterBuffer = new BYTE[nOffset]);
- if (m_pParameterBuffer == NULL)
- {
- // Note that pNamesBuffer will be freed in the destructor
- // by freeing *m_ppParamName
- CoTaskMemFree(pParamInfo);
- return E_OUTOFMEMORY;
- }
- *ppParameterBuffer = m_pParameterBuffer;
- m_nParameterBufferSize = nOffset;
- m_nParams = ulParams;
- BindEntries(m_pParameterEntry, ulParams, pHAccessor, nOffset, spAccessor);
-
- CoTaskMemFree(pParamInfo);
-
- return S_OK;
- }
- bool HasParameters() const
- {
- return true;
- }
- HRESULT AllocateParameterInfo(int nParamEntries)
- {
- // Allocate memory for the bind structures
- m_pParameterEntry = NULL;
- ATLTRY(m_pParameterEntry = new DBBINDING[nParamEntries]);
- if (m_pParameterEntry == NULL)
- return E_OUTOFMEMORY;
-
- // Allocate memory to store the field names
- m_ppParamName = NULL;
- ATLTRY(m_ppParamName = new OLECHAR*[nParamEntries]);
- if (m_ppParamName == NULL)
- return E_OUTOFMEMORY;
- return S_OK;
- }
-
- // Data Members
- // Number of parameters
- ULONG m_nParams;
- // A pointer to the entry structures for each parameter
- DBBINDING* m_pParameterEntry;
- // String names for the parameters
- OLECHAR** m_ppParamName;
- // The size of the buffer where the parameters are stored
- ULONG m_nParameterBufferSize;
- // A pointer to the buffer where the parameters are stored
- BYTE* m_pParameterBuffer;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CManualAccessor
-
- class CManualAccessor :
- public CAccessorBase
- {
- public:
- CManualAccessor()
- {
- // By default we don't have any parameters unless CreateParameterAccessor is called
- m_pEntry = NULL;
- m_nParameters = 0;
- m_pParameterEntry = NULL;
- m_nColumns = 0;
- }
- ~CManualAccessor()
- {
- delete [] m_pEntry;
- delete [] m_pParameterEntry;
- }
- HRESULT CreateAccessor(int nBindEntries, void* pBuffer, ULONG nBufferSize)
- {
- m_pBuffer = (BYTE*)pBuffer;
- m_nBufferSize = nBufferSize;
- m_nColumns = nBindEntries;
- m_nEntry = 0;
-
- // If they've previously created some entries then free them
- delete [] m_pEntry;
- m_pEntry = NULL;
-
- // Allocate memory for the bind structures
- ATLTRY(m_pEntry = new DBBINDING[nBindEntries]);
- if (m_pEntry == NULL)
- return E_OUTOFMEMORY;
- else
- return S_OK;
- }
- HRESULT CreateParameterAccessor(int nBindEntries, void* pBuffer, ULONG nBufferSize)
- {
- m_pParameterBuffer = (BYTE*)pBuffer;
- m_nParameterBufferSize = nBufferSize;
- m_nParameters = nBindEntries;
- m_nCurrentParameter = 0;
-
- // Allocate memory for the bind structures
- m_pParameterEntry = NULL;
- ATLTRY(m_pParameterEntry = new DBBINDING[nBindEntries]);
- if (m_pParameterEntry == NULL)
- return E_OUTOFMEMORY;
- else
- return S_OK;
- }
- void AddBindEntry(ULONG nOrdinal, DBTYPE wType, ULONG nColumnSize,
- void* pData, void* pLength = NULL, void* pStatus = NULL)
- {
- ATLASSERT(m_nEntry < m_nColumns);
- ULONG nLengthOffset, nStatusOffset;
-
- if (pStatus != NULL)
- nStatusOffset = (BYTE*)pStatus - m_pBuffer;
- else
- nStatusOffset = 0;
-
- if (pLength != NULL)
- nLengthOffset = (BYTE*)pLength - m_pBuffer;
- else
- nLengthOffset = 0;
-
- Bind(m_pEntry+m_nEntry, nOrdinal, wType, nColumnSize, 0, 0, DBPARAMIO_NOTPARAM,
- (BYTE*)pData - m_pBuffer, nLengthOffset, nStatusOffset);
-
- m_nEntry++;
- }
- void AddParameterEntry(ULONG nOrdinal, DBTYPE wType, ULONG nColumnSize,
- void* pData, void* pLength = NULL, void* pStatus = NULL,
- DBPARAMIO eParamIO = DBPARAMIO_INPUT)
- {
- ATLASSERT(m_nCurrentParameter < m_nParameters);
- ULONG nLengthOffset, nStatusOffset;
-
- if (pStatus != NULL)
- nStatusOffset = (BYTE*)pStatus - m_pParameterBuffer;
- else
- nStatusOffset = 0;
-
- if (pLength != NULL)
- nLengthOffset = (BYTE*)pLength - m_pBuffer;
- else
- nLengthOffset = 0;
-
- Bind(m_pParameterEntry + m_nCurrentParameter, nOrdinal, wType, nColumnSize, 0, 0,
- eParamIO, (BYTE*)pData - m_pParameterBuffer, nLengthOffset, nStatusOffset);
-
- m_nCurrentParameter++;
- }
-
- // Implementation
- // Free's any columns in the current record that need to be freed.
- // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
- void FreeRecordMemory(IRowset* pRowset)
- {
- ULONG i;
-
- for (i = 0; i < m_nColumns; i++)
- CAccessorBase::FreeType(m_pEntry[i].wType, m_pBuffer + m_pEntry[i].obValue, pRowset);
- }
- HRESULT BindColumns(IUnknown* pUnk)
- {
- ATLASSERT(pUnk != NULL);
- CComPtr<IAccessor> spAccessor;
- HRESULT hr = pUnk->QueryInterface(&spAccessor);
- if (FAILED(hr))
- return hr;
-
- // Allocate the accessor memory if we haven't done so yet
- if (m_pAccessorInfo == NULL)
- {
- hr = AllocateAccessorMemory(1); // We only have one accessor
- if (FAILED(hr))
- return hr;
- m_pAccessorInfo->bAutoAccessor = TRUE;
- }
-
- return BindEntries(m_pEntry, m_nColumns, &m_pAccessorInfo->hAccessor, m_nBufferSize, spAccessor);
- }
-
- HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer)
- {
- HRESULT hr;
- *ppParameterBuffer = m_pParameterBuffer;
-
- // Only bind the parameter if we haven't done so yet
- if (*pHAccessor == NULL)
- {
- // Get the IAccessor from the passed IUnknown
- CComPtr<IAccessor> spAccessor;
- hr = pCommand->QueryInterface(&spAccessor);
- if (SUCCEEDED(hr))
- {
- hr = BindEntries(m_pParameterEntry, m_nParameters, pHAccessor,
- m_nParameterBufferSize, spAccessor);
- }
- }
- else
- hr = S_OK;
-
- return hr;
- }
- typedef CManualAccessor _ParamClass;
- bool HasParameters() { return (m_nParameters > 0); }
- typedef CManualAccessor _OutputColumnsClass;
- static bool HasOutputColumns() { return true; }
- ULONG GetColumnCount() const
- {
- return m_nColumns;
- }
-
- // The binding structure for the output columns
- DBBINDING* m_pEntry;
- // The number of output columns
- ULONG m_nColumns;
- // The number of the current entry for the output columns
- ULONG m_nEntry;
- // The size of the data buffer for the output columns
- ULONG m_nBufferSize;
- // The number of parameters columns
- ULONG m_nParameters;
- // The number of the parameter column to bind next
- ULONG m_nCurrentParameter;
- // A pointer to the entry structures for each parameter
- DBBINDING* m_pParameterEntry;
- // The size of the buffer where the parameters are stored
- ULONG m_nParameterBufferSize;
- // A pointer to the buffer where the parameters are stored
- BYTE* m_pParameterBuffer;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // CAccessorRowset
-
- template <class TAccessor = CNoAccessor, class TRowset = CRowset>
- class CAccessorRowset :
- public TAccessor,
- public TRowset
- {
- public:
- CAccessorRowset()
- {
- // Give the rowset a pointer to the accessor
- SetAccessor(this);
- }
- ~CAccessorRowset()
- {
- Close();
- }
- // Used to get the column information from the opened rowset. The user is responsible
- // for freeing the returned column information and string buffer.
- HRESULT GetColumnInfo(ULONG* pulColumns,
- DBCOLUMNINFO** ppColumnInfo, LPOLESTR* ppStrings) const
- {
- ATLASSERT(GetInterface() != NULL);
- if (ppColumnInfo == NULL || pulColumns == NULL || ppStrings == NULL)
- return E_POINTER;
-
- CComPtr<IColumnsInfo> spColumns;
- HRESULT hr = GetInterface()->QueryInterface(&spColumns);
- if (SUCCEEDED(hr))
- hr = spColumns->GetColumnInfo(pulColumns, ppColumnInfo, ppStrings);
-
- return hr;
- }
- // Used to get the column information when overriding the bindings using CDynamicAccessor
- // The user should CoTaskMemFree the column information pointer that is returned.
- HRESULT GetColumnInfo(ULONG* pColumns, DBCOLUMNINFO** ppColumnInfo)
- {
- // If you get a compilation here, then you are most likely calling this function
- // from a class that is not using CDynamicAccessor.
- ATLASSERT(GetInterface() != NULL);
- return TAccessor::GetColumnInfo(GetInterface(), pColumns, ppColumnInfo);
- }
- // Call to bind the output columns
- HRESULT Bind()
- {
- // Bind should only be called when we've successfully opened the rowset
- ATLASSERT(GetInterface() != NULL);
- HRESULT hr = TAccessor::BindColumns(GetInterface());
- if (SUCCEEDED(hr))
- hr = BindFinished();
- return hr;
- }
- // Close the opened rowset and release the created accessors for the output columns
- void Close()
- {
- if (GetInterface() != NULL)
- {
- ReleaseAccessors(GetInterface());
- TAccessor::Close();
- TRowset::Close();
- }
- }
- // Free's any columns in the current record that need to be freed.
- // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
- void FreeRecordMemory()
- {
- TAccessor::FreeRecordMemory(m_spRowset);
- }
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CEnumeratorAccessor
-
- class CEnumeratorAccessor
- {
- public:
- WCHAR m_szName[129];
- WCHAR m_szParseName[129];
- WCHAR m_szDescription[129];
- USHORT m_nType;
- VARIANT_BOOL m_bIsParent;
-
- // Binding Maps
- BEGIN_COLUMN_MAP(CEnumeratorAccessor)
- COLUMN_ENTRY(1, m_szName)
- COLUMN_ENTRY(2, m_szParseName)
- COLUMN_ENTRY(3, m_szDescription)
- COLUMN_ENTRY(4, m_nType)
- COLUMN_ENTRY(5, m_bIsParent)
- END_COLUMN_MAP()
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CEnumerator
-
- class CEnumerator : public CAccessorRowset<CAccessor<CEnumeratorAccessor> >
- {
- public:
- HRESULT Open(LPMONIKER pMoniker)
- {
- if (pMoniker == NULL)
- return E_FAIL;
-
- // Bind the moniker for the sources rowset
- if (FAILED(BindMoniker(pMoniker, 0, IID_ISourcesRowset,
- (void**)&m_spSourcesRowset)))
- return E_FAIL;
-
- // Enumerate the data sources
- if (FAILED(m_spSourcesRowset->GetSourcesRowset(NULL, IID_IRowset, 0,
- NULL, (IUnknown**)&m_spRowset)))
- return E_FAIL;
-
- return Bind();
- }
- HRESULT Open(const CEnumerator& enumerator)
- {
- HRESULT hr;
- CComPtr<IMoniker> spMoniker;
-
- hr = enumerator.GetMoniker(&spMoniker);
- if (FAILED(hr))
- return hr;
-
- return Open(spMoniker);
- }
- HRESULT Open(const CLSID* pClsid = &CLSID_OLEDB_ENUMERATOR)
- {
- if (pClsid == NULL)
- return E_FAIL;
-
- HRESULT hr;
- // Create the enumerator
- hr = CoCreateInstance(*pClsid, NULL, CLSCTX_INPROC_SERVER,
- IID_ISourcesRowset, (LPVOID*)&m_spSourcesRowset);
- if (FAILED(hr))
- return hr;
-
- // Get the rowset so we can enumerate the data sources
- hr = m_spSourcesRowset->GetSourcesRowset(NULL, IID_IRowset, 0,
- NULL, (IUnknown**)&m_spRowset);
- if (FAILED(hr))
- return hr;
-
- return Bind();
- }
-
- HRESULT GetMoniker(LPMONIKER* ppMoniker) const
- {
- CComPtr<IParseDisplayName> spParse;
- HRESULT hr;
- ULONG chEaten;
-
- if (ppMoniker == NULL)
- return E_POINTER;
-
- if (m_spSourcesRowset == NULL)
- return E_FAIL;
-
- hr = m_spSourcesRowset->QueryInterface(IID_IParseDisplayName, (void**)&spParse);
- if (FAILED(hr))
- return hr;
-
- hr = spParse->ParseDisplayName(NULL, (LPOLESTR)m_szParseName,
- &chEaten, ppMoniker);
- return hr;
- }
-
- HRESULT GetMoniker(LPMONIKER* ppMoniker, LPCTSTR lpszDisplayName) const
- {
- USES_CONVERSION;
- CComPtr<IParseDisplayName> spParse;
- HRESULT hr;
- ULONG chEaten;
-
- if (ppMoniker == NULL || lpszDisplayName == NULL)
- return E_POINTER;
-
- if (m_spSourcesRowset == NULL)
- return E_FAIL;
-
- hr = m_spSourcesRowset->QueryInterface(IID_IParseDisplayName, (void**)&spParse);
- if (FAILED(hr))
- return hr;
-
- hr = spParse->ParseDisplayName(NULL, (LPOLESTR)T2COLE(lpszDisplayName),
- &chEaten, ppMoniker);
- return hr;
- }
-
- bool Find(TCHAR* szSearchName)
- {
- USES_CONVERSION;
- // Loop through the providers looking for the passed name
- while (MoveNext()==S_OK && lstrcmp(W2T(m_szName), szSearchName))
- ATLTRACE2(atlTraceDBClient, 0, _T("%s, %s, %d\n"), W2T(m_szName), W2T(m_szParseName), m_nType);
- if (lstrcmp(W2T(m_szName), szSearchName))
- return false;
- else
- return true;
- }
-
- CComPtr<ISourcesRowset> m_spSourcesRowset;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // CDataSource
-
- class CDataSource
- {
- public:
- HRESULT Open(const CLSID& clsid, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
- {
- HRESULT hr;
-
- m_spInit.Release();
- hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize,
- (void**)&m_spInit);
- if (FAILED(hr))
- return hr;
-
- // Initialize the provider
- return OpenWithProperties(pPropSet, nPropertySets);
- }
- HRESULT Open(const CLSID& clsid, LPCTSTR pName, LPCTSTR pUserName = NULL,
- LPCTSTR pPassword = NULL, long nInitMode = 0)
- {
- HRESULT hr;
-
- m_spInit.Release();
- hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize,
- (void**)&m_spInit);
- if (FAILED(hr))
- return hr;
-
- return OpenWithNameUserPassword(pName, pUserName, pPassword, nInitMode);
- }
- HRESULT Open(LPCTSTR szProgID, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
- {
- USES_CONVERSION;
- HRESULT hr;
- CLSID clsid;
-
- hr = CLSIDFromProgID(T2COLE(szProgID), &clsid);
- if (FAILED(hr))
- return hr;
-
- return Open(clsid, pPropSet, nPropertySets);
- }
- HRESULT Open(LPCTSTR szProgID, LPCTSTR pName, LPCTSTR pUserName = NULL,
- LPCTSTR pPassword = NULL, long nInitMode = 0)
- {
- USES_CONVERSION;
- HRESULT hr;
- CLSID clsid;
-
- hr = CLSIDFromProgID(T2COLE(szProgID), &clsid);
- if (FAILED(hr))
- return hr;
-
- return Open(clsid, pName, pUserName, pPassword, nInitMode);
- }
- HRESULT Open(const CEnumerator& enumerator, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
- {
- CComPtr<IMoniker> spMoniker;
- HRESULT hr;
-
- hr = enumerator.GetMoniker(&spMoniker);
- if (FAILED(hr))
- return hr;
-
- m_spInit.Release();
- // Now bind the moniker
- hr = BindMoniker(spMoniker, 0, IID_IDBInitialize, (void**)&m_spInit);
- if (FAILED(hr))
- return hr;
-
- return OpenWithProperties(pPropSet, nPropertySets);
- }
- HRESULT Open(const CEnumerator& enumerator, LPCTSTR pName, LPCTSTR pUserName = NULL,
- LPCTSTR pPassword = NULL, long nInitMode = 0)
- {
- CComPtr<IMoniker> spMoniker;
- HRESULT hr;
-
- hr = enumerator.GetMoniker(&spMoniker);
- if (FAILED(hr))
- return hr;
-
- m_spInit.Release();
- // Now bind the moniker
- hr = BindMoniker(spMoniker, 0, IID_IDBInitialize, (void**)&m_spInit);
- if (FAILED(hr))
- return hr;
-
- return OpenWithNameUserPassword(pName, pUserName, pPassword, nInitMode);
- }
- // Invoke the data links dialog and open the selected database
- HRESULT Open(HWND hWnd = GetActiveWindow(), DBPROMPTOPTIONS dwPromptOptions = DBPROMPTOPTIONS_WIZARDSHEET)
- {
- CComPtr<IDBPromptInitialize> spDBInit;
-
- HRESULT hr = CoCreateInstance(CLSID_DataLinks, NULL, CLSCTX_INPROC_SERVER,
- IID_IDBPromptInitialize, (void**) &spDBInit);
- if (FAILED(hr))
- return hr;
-
- CComPtr<IDBProperties> spIDBProperties;
- hr = spDBInit->PromptDataSource(NULL, hWnd, dwPromptOptions, 0, NULL, NULL,
- IID_IDBProperties, (IUnknown**)&spIDBProperties);
-
- if (hr == S_OK)
- {
- hr = spIDBProperties->QueryInterface(&m_spInit);
- if (SUCCEEDED(hr))
- hr = m_spInit->Initialize();
- }
- else if (hr == S_FALSE)
- hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CANCELLED); // The user clicked cancel
-
- return hr;
- }
- // Opens a data source using the service components
- HRESULT OpenWithServiceComponents(const CLSID& clsid, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
- {
- CComPtr<IDataInitialize> spDataInit;
- HRESULT hr;
-
- hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
- IID_IDataInitialize, (void**)&spDataInit);
- if (FAILED(hr))
- return hr;
-
- m_spInit.Release();
- hr = spDataInit->CreateDBInstance(clsid, NULL, CLSCTX_INPROC_SERVER, NULL,
- IID_IDBInitialize, (IUnknown**)&m_spInit);
- if (FAILED(hr))
- return hr;
-
- // Initialize the provider
- return OpenWithProperties(pPropSet, nPropertySets);
- }
- // Opens a data source using the service components
- HRESULT OpenWithServiceComponents(LPCTSTR szProgID, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1)
- {
- USES_CONVERSION;
- HRESULT hr;
- CLSID clsid;
-
- hr = CLSIDFromProgID(T2COLE(szProgID), &clsid);
- if (FAILED(hr))
- return hr;
-
- return OpenWithServiceComponents(clsid, pPropSet, nPropertySets);
- }
- // Bring up the "Organize Dialog" which allows the user to select a previously created data link
- // file (.UDL file). The selected file will be used to open the datbase.
- HRESULT OpenWithPromptFileName(HWND hWnd = GetActiveWindow(), DBPROMPTOPTIONS dwPromptOptions = DBPROMPTOPTIONS_NONE,
- LPCOLESTR szInitialDirectory = NULL)
- {
- USES_CONVERSION;
- CComPtr<IDBPromptInitialize> spDBInit;
-
- HRESULT hr = CoCreateInstance(CLSID_DataLinks, NULL, CLSCTX_INPROC_SERVER,
- IID_IDBPromptInitialize, (void**) &spDBInit);
- if (FAILED(hr))
- return hr;
-
- CComPtr<IDBProperties> spIDBProperties;
- LPOLESTR szSelected;
-
- hr = spDBInit->PromptFileName(hWnd, dwPromptOptions, szInitialDirectory, L"*.udl", &szSelected);
-
- if (hr == S_OK)
- hr = OpenFromFileName(szSelected);
- else if (hr == S_FALSE)
- hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CANCELLED); // The user clicked cancel
-
- return hr;
- }
- // Open the datasource specified by the passed filename, typically a .UDL file
- HRESULT OpenFromFileName(LPCOLESTR szFileName)
- {
- CComPtr<IDataInitialize> spDataInit;
- LPOLESTR szInitString;
-
- HRESULT hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
- IID_IDataInitialize, (void**)&spDataInit);
- if (FAILED(hr))
- return hr;
-
- hr = spDataInit->LoadStringFromStorage(szFileName, &szInitString);
- if (FAILED(hr))
- return hr;
-
- return OpenFromInitializationString(szInitString);
- }
- // Open the datasource specified by the passed initialization string
- HRESULT OpenFromInitializationString(LPCOLESTR szInitializationString)
- {
- CComPtr<IDataInitialize> spDataInit;
-
- HRESULT hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
- IID_IDataInitialize, (void**)&spDataInit);
- if (FAILED(hr))
- return hr;
-
- CComPtr<IDBProperties> spIDBProperties;
- hr = spDataInit->GetDataSource(NULL, CLSCTX_INPROC_SERVER, szInitializationString,
- IID_IDBInitialize, (IUnknown**)&m_spInit);
- if (FAILED(hr))
- return hr;
-
- return m_spInit->Initialize();
- }
- // Get the initialization string from the currently open data source. The returned string
- // must be CoTaskMemFree'd when finished with.
- HRESULT GetInitializationString(BSTR* pInitializationString, bool bIncludePassword=false)
- {
- // If the datasource isn't open then we're not going to get an init string
- _ASSERTE(m_spInit != NULL);
- CComPtr<IDataInitialize> spDataInit;
- LPOLESTR szInitString;
-
- HRESULT hr = CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,
- IID_IDataInitialize, (void**)&spDataInit);
- if (FAILED(hr))
- return hr;
-
- hr = spDataInit->GetInitializationString(m_spInit, bIncludePassword, &szInitString);
-
- if (SUCCEEDED(hr))
- *pInitializationString = ::SysAllocString(szInitString);
-
- return hr;
- }
- HRESULT GetProperties(ULONG ulPropIDSets, const DBPROPIDSET* pPropIDSet,
- ULONG* pulPropertySets, DBPROPSET** ppPropsets) const
- {
- CComPtr<IDBProperties> spProperties;
-
- // Check that we are connected
- ATLASSERT(m_spInit != NULL);
-
- HRESULT hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
- if (FAILED(hr))
- return hr;
-
- hr = spProperties->GetProperties(ulPropIDSets, pPropIDSet, pulPropertySets,
- ppPropsets);
- return hr;
- }
-
- HRESULT GetProperty(const GUID& guid, DBPROPID propid, VARIANT* pVariant) const
- {
- ATLASSERT(pVariant != NULL);
- CComPtr<IDBProperties> spProperties;
-
- // Check that we are connected
- ATLASSERT(m_spInit != NULL);
-
- HRESULT hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
- if (FAILED(hr))
- return hr;
-
- CDBPropIDSet set(guid);
- set.AddPropertyID(propid);
- DBPROPSET* pPropSet = NULL;
- ULONG ulPropSet = 0;
- hr = spProperties->GetProperties(1, &set, &ulPropSet, &pPropSet);
- if (FAILED(hr))
- return hr;
-
- ATLASSERT(ulPropSet == 1);
- VariantCopy(pVariant, &pPropSet->rgProperties[0].vValue);
- CoTaskMemFree(pPropSet->rgProperties);
- CoTaskMemFree(pPropSet);
-
- return S_OK;
- }
- void Close()
- {
- m_spInit.Release();
- }
-
- // Implementation
- HRESULT OpenFromIDBProperties(IDBProperties* pIDBProperties)
- {
- CComPtr<IPersist> spPersist;
- CLSID clsid;
- HRESULT hr;
-
- hr = pIDBProperties->QueryInterface(IID_IPersist, (void**)&spPersist);
- if (FAILED(hr))
- return hr;
-
- spPersist->GetClassID(&clsid);
-
- ULONG ulPropSets=0;
- CDBPropSet* pPropSets=NULL;
- pIDBProperties->GetProperties(0, NULL, &ulPropSets, (DBPROPSET**)&pPropSets);
-
- hr = Open(clsid, &pPropSets[0], ulPropSets);
-
- for (ULONG i=0; i < ulPropSets; i++)
- (pPropSets+i)->~CDBPropSet();
- CoTaskMemFree(pPropSets);
-
- return hr;
- }
- HRESULT OpenWithNameUserPassword(LPCTSTR pName, LPCTSTR pUserName, LPCTSTR pPassword, long nInitMode = 0)
- {
- ATLASSERT(m_spInit != NULL);
- CComPtr<IDBProperties> spProperties;
- HRESULT hr;
-
- hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
- if (FAILED(hr))
- return hr;
-
- // Set connection properties
- CDBPropSet propSet(DBPROPSET_DBINIT);
-
- // Add Datbase name, User name and Password
- if (pName != NULL)
- propSet.AddProperty(DBPROP_INIT_DATASOURCE, pName);
-
- if (pUserName != NULL)
- propSet.AddProperty(DBPROP_AUTH_USERID, pUserName);
-
- if (pPassword != NULL)
- propSet.AddProperty(DBPROP_AUTH_PASSWORD, pPassword);
-
- if (nInitMode)
- propSet.AddProperty(DBPROP_INIT_MODE, nInitMode);
-
- hr = spProperties->SetProperties(1, &propSet);
- if (FAILED(hr))
- return hr;
-
- // Initialize the provider
- return m_spInit->Initialize();
- }
- HRESULT OpenWithProperties(DBPROPSET* pPropSet, ULONG nPropertySets=1)
- {
- ATLASSERT(m_spInit != NULL);
-
- // Set the properties if there are some to set
- if (pPropSet != NULL)
- {
- CComPtr<IDBProperties> spProperties;
- HRESULT hr;
-
- hr = m_spInit->QueryInterface(IID_IDBProperties, (void**)&spProperties);
- if (FAILED(hr))
- return hr;
-
- hr = spProperties->SetProperties(nPropertySets, pPropSet);
- if (FAILED(hr))
- return hr;
- }
-
- // Initialize the provider
- return m_spInit->Initialize();
- }
-
- CComPtr<IDBInitialize> m_spInit;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // class CSession
-
- class CSession
- {
- public:
- // Create a session on the passed datasource
- HRESULT Open(const CDataSource& ds)
- {
- CComPtr<IDBCreateSession> spSession;
-
- // Check we have connected to the database
- ATLASSERT(ds.m_spInit != NULL);
-
- HRESULT hr = ds.m_spInit->QueryInterface(IID_IDBCreateSession, (void**)&spSession);
- if (FAILED(hr))
- return hr;
-
- hr = spSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown**)&m_spOpenRowset);
- return hr;
- }
- // Close the session
- void Close()
- {
- m_spOpenRowset.Release();
- }
- // Start a transaction
- HRESULT StartTransaction(ISOLEVEL isoLevel = ISOLATIONLEVEL_READCOMMITTED, ULONG isoFlags = 0,
- ITransactionOptions* pOtherOptions = NULL, ULONG* pulTransactionLevel = NULL) const
- {
- ATLASSERT(m_spOpenRowset != NULL);
- CComPtr<ITransactionLocal> spTransactionLocal;
- HRESULT hr = m_spOpenRowset->QueryInterface(&spTransactionLocal);
-
- if (SUCCEEDED(hr))
- hr = spTransactionLocal->StartTransaction(isoLevel, isoFlags, pOtherOptions, pulTransactionLevel);
-
- return hr;
- }
- // Abort the current transaction
- HRESULT Abort(BOID* pboidReason = NULL, BOOL bRetaining = FALSE, BOOL bAsync = FALSE) const
- {
- ATLASSERT(m_spOpenRowset != NULL);
- CComPtr<ITransaction> spTransaction;
- HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
-
- if (SUCCEEDED(hr))
- hr = spTransaction->Abort(pboidReason, bRetaining, bAsync);
-
- return hr;
- }
- // Commit the current transaction
- HRESULT Commit(BOOL bRetaining = FALSE, DWORD grfTC = XACTTC_SYNC, DWORD grfRM = 0) const
- {
- ATLASSERT(m_spOpenRowset != NULL);
- CComPtr<ITransaction> spTransaction;
- HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
-
- if (SUCCEEDED(hr))
- hr = spTransaction->Commit(bRetaining, grfTC, grfRM);
-
- return hr;
- }
- // Get information for the current transaction
- HRESULT GetTransactionInfo(XACTTRANSINFO* pInfo) const
- {
- ATLASSERT(m_spOpenRowset != NULL);
- CComPtr<ITransaction> spTransaction;
- HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
-
- if (SUCCEEDED(hr))
- hr = spTransaction->GetTransactionInfo(pInfo);
-
- return hr;
- }
- // Implementation
- CComPtr<IOpenRowset> m_spOpenRowset;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // CTable
-
- template <class TAccessor = CNoAccessor, class TRowset = CRowset>
- class CTable :
- public CAccessorRowset<TAccessor, TRowset>
- {
- public:
- // Open a rowset on the passed name
- HRESULT Open(const CSession& session, LPCTSTR szTableName, DBPROPSET* pPropSet = NULL)
- {
- USES_CONVERSION;
- DBID idTable;
-
- idTable.eKind = DBKIND_NAME;
- idTable.uName.pwszName = (LPOLESTR)T2COLE(szTableName);
-
- return Open(session, idTable, pPropSet);
- }
- // Open the a rowset on the passed DBID
- HRESULT Open(const CSession& session, DBID& dbid, DBPROPSET* pPropSet = NULL)
- {
- // Check the session is valid
- ATLASSERT(session.m_spOpenRowset != NULL);
- HRESULT hr;
-
- hr = session.m_spOpenRowset->OpenRowset(NULL, &dbid, NULL, GetIID(),
- (pPropSet) ? 1 : 0, pPropSet, (IUnknown**)GetInterfacePtr());
- if (SUCCEEDED(hr))
- {
- SetupOptionalRowsetInterfaces();
-
- // If we have output columns then bind
- if (_OutputColumnsClass::HasOutputColumns())
- hr = Bind();
- }
-
- return hr;
- }
- };
-
- #if (OLEDBVER < 0x0150)
- #define DBGUID_DEFAULT DBGUID_DBSQL
- #endif
-
-
- ///////////////////////////////////////////////////////////////////////////
- // CCommandBase
-
- class CCommandBase
- {
- public:
- CCommandBase()
- {
- m_hParameterAccessor = NULL;
- }
-
- ~CCommandBase()
- {
- ReleaseCommand();
- }
- // Create the command
- HRESULT CreateCommand(const CSession& session)
- {
- // Before creating the command, release the old one if necessary.
- ReleaseCommand();
-
- // Check the session is valid
- ATLASSERT(session.m_spOpenRowset != NULL);
-
- CComPtr<IDBCreateCommand> spCreateCommand;
-
- HRESULT hr = session.m_spOpenRowset->QueryInterface(IID_IDBCreateCommand, (void**)&spCreateCommand);
- if (FAILED(hr))
- return hr;
-
- return spCreateCommand->CreateCommand(NULL, IID_ICommand, (IUnknown**)&m_spCommand);
- }
- // Prepare the command
- HRESULT Prepare(ULONG cExpectedRuns = 0)
- {
- CComPtr<ICommandPrepare> spCommandPrepare;
- HRESULT hr = m_spCommand->QueryInterface(&spCommandPrepare);
- if (SUCCEEDED(hr))
- hr = spCommandPrepare->Prepare(cExpectedRuns);
-
- return hr;
- }
- // Unprepare the command
- HRESULT Unprepare()
- {
- CComPtr<ICommandPrepare> spCommandPrepare;
- HRESULT hr = m_spCommand->QueryInterface(&spCommandPrepare);
- if (SUCCEEDED(hr))
- hr = spCommandPrepare->Unprepare();
-
- return hr;
- }
- // Create the command and set the command text
- HRESULT Create(const CSession& session, LPCTSTR szCommand,
- REFGUID guidCommand = DBGUID_DEFAULT)
- {
- USES_CONVERSION;
- HRESULT hr;
-
- hr = CreateCommand(session);
- if (SUCCEEDED(hr))
- {
- CComPtr<ICommandText> spCommandText;
- hr = m_spCommand->QueryInterface(&spCommandText);
- if (SUCCEEDED(hr))
- hr = spCommandText->SetCommandText(guidCommand, T2COLE(szCommand));
- }
- return hr;
- }
- // Release the command
- void ReleaseCommand()
- {
- // Release the parameter accessor if necessary, before releasing the command
- if (m_hParameterAccessor != NULL)
- {
- CComPtr<IAccessor> spAccessor;
- HRESULT hr = m_spCommand->QueryInterface(&spAccessor);
- if (SUCCEEDED(hr))
- {
- spAccessor->ReleaseAccessor(m_hParameterAccessor, NULL); \
- m_hParameterAccessor = NULL;
- }
- }
- m_spCommand.Release();
- }
- // Get the parameter information from the command
- HRESULT GetParameterInfo(ULONG* pParams, DBPARAMINFO** ppParamInfo,
- OLECHAR** ppNamesBuffer)
- {
- CComPtr<ICommandWithParameters> spCommandParameters;
- HRESULT hr = m_spCommand->QueryInterface(&spCommandParameters);
- if (SUCCEEDED(hr))
- {
- // Get the parameter information
- hr = spCommandParameters->GetParameterInfo(pParams, ppParamInfo,
- ppNamesBuffer);
- }
- return hr;
- }
- // Set the parameter information for the command
- HRESULT SetParameterInfo(ULONG ulParams, const ULONG* pOrdinals,
- const DBPARAMBINDINFO* pParamInfo)
- {
- CComPtr<ICommandWithParameters> spCommandParameters;
- HRESULT hr = m_spCommand->QueryInterface(&spCommandParameters);
- if (SUCCEEDED(hr))
- {
- // Set the parameter information
- hr = spCommandParameters->SetParameterInfo(ulParams, pOrdinals,
- pParamInfo);
- }
- return hr;
- }
-
- CComPtr<ICommand> m_spCommand;
- HACCESSOR m_hParameterAccessor;
- };
-
- // Used to turn on multiple result set support in CCommand
- class CMultipleResults
- {
- public:
- bool UseMultipleResults() { return true; }
- IMultipleResults** GetMultiplePtrAddress() { return &m_spMultipleResults.p; }
- IMultipleResults* GetMultiplePtr() { return m_spMultipleResults; }
-
- CComPtr<IMultipleResults> m_spMultipleResults;
- };
-
- // Used to turn off multiple result set support in CCommand
- class CNoMultipleResults
- {
- public:
- bool UseMultipleResults() { return false; }
- IMultipleResults** GetMultiplePtrAddress() { return NULL; }
- IMultipleResults* GetMultiplePtr() { return NULL; }
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // CCommand
-
- template <class TAccessor = CNoAccessor, class TRowset = CRowset, class TMultiple = CNoMultipleResults>
- class CCommand :
- public CAccessorRowset<TAccessor, TRowset>,
- public CCommandBase,
- public TMultiple
- {
- public:
- // Create a command on the session and execute it
- HRESULT Open(const CSession& session, LPCTSTR szCommand = NULL,
- DBPROPSET *pPropSet = NULL, LONG* pRowsAffected = NULL,
- REFGUID guidCommand = DBGUID_DEFAULT, bool bBind = true)
- {
- HRESULT hr;
- if (szCommand == NULL)
- {
- hr = _CommandClass::GetDefaultCommand(&szCommand);
- if (FAILED(hr))
- return hr;
- }
- hr = Create(session, szCommand, guidCommand);
- if (FAILED(hr))
- return hr;
-
- return Open(pPropSet, pRowsAffected, bBind);
- }
- // Used if you have previously created the command
- HRESULT Open(DBPROPSET *pPropSet = NULL, LONG* pRowsAffected = NULL, bool bBind = true)
- {
- HRESULT hr;
- DBPARAMS params;
- DBPARAMS *pParams;
-
- // Bind the parameters if we have some
- if (_ParamClass::HasParameters())
- {
- // Bind the parameters in the accessor if they haven't already been bound
- hr = BindParameters(&m_hParameterAccessor, m_spCommand, ¶ms.pData);
- if (FAILED(hr))
- return hr;
-
- // Setup the DBPARAMS structure
- params.cParamSets = 1;
- params.hAccessor = m_hParameterAccessor;
- pParams = ¶ms;
- }
- else
- pParams = NULL;
-
- hr = Execute(GetInterfacePtr(), pParams, pPropSet, pRowsAffected);
- if (FAILED(hr))
- return hr;
-
- // Only bind if we have been asked to and we have output columns
- if (bBind && _OutputColumnsClass::HasOutputColumns())
- return Bind();
- else
- return hr;
- }
- // Get the next rowset when using multiple result sets
- HRESULT GetNextResult(LONG* pulRowsAffected, bool bBind = true)
- {
- // This function should only be called if CMultipleResults is being
- // used as the third template parameter
- ATLASSERT(GetMultiplePtrAddress() != NULL);
-
- // If user calls GetNextResult but the interface is not available
- // return E_FAIL.
- if (GetMultiplePtr() == NULL)
- return E_FAIL;
-
- // Close the existing rowset in preparation for opening the next one
- Close();
-
- HRESULT hr = GetMultiplePtr()->GetResult(NULL, 0, IID_IRowset,
- pulRowsAffected, (IUnknown**)GetInterfacePtr());
- if (FAILED(hr))
- return hr;
-
- if (bBind && GetInterface() != NULL)
- return Bind();
- else
- return hr;
- }
-
- // Implementation
- HRESULT Execute(IRowset** ppRowset, DBPARAMS* pParams, DBPROPSET *pPropSet, LONG* pRowsAffected)
- {
- HRESULT hr;
-
- // Specify the properties if we have some
- if (pPropSet)
- {
- CComPtr<ICommandProperties> spCommandProperties;
- hr = m_spCommand->QueryInterface(&spCommandProperties);
- if (FAILED(hr))
- return hr;
-
- hr = spCommandProperties->SetProperties(1, pPropSet);
- if (FAILED(hr))
- return hr;
- }
-
- // If the user want the rows affected then return it back, otherwise
- // just point to our local variable here.
- LONG nAffected, *pAffected;
- if (pRowsAffected)
- pAffected = pRowsAffected;
- else
- pAffected = &nAffected;
-
- if (UseMultipleResults())
- {
- hr = m_spCommand->Execute(NULL, IID_IMultipleResults, pParams,
- pAffected, (IUnknown**)GetMultiplePtrAddress());
-
- if (SUCCEEDED(hr))
- {
- hr = GetNextResult(pAffected, false);
- }
- else
- {
- // If we can't get IMultipleResults then just try to get IRowset
- hr = m_spCommand->Execute(NULL, IID_IRowset, pParams, pAffected,
- (IUnknown**)GetInterfacePtr());
- }
- }
- else
- {
- hr = m_spCommand->Execute(NULL, GetIID(), pParams, pAffected,
- (IUnknown**)ppRowset);
- if (SUCCEEDED(hr))
- SetupOptionalRowsetInterfaces();
- }
- return hr;
- }
- };
-
-
- // This class can be used to implement the IRowsetNotify interface.
- // It is supplied so that if you only want to implement one of the
- // notifications you don't have to supply empty functions for the
- // other methods.
- class ATL_NO_VTABLE IRowsetNotifyImpl : public IRowsetNotify
- {
- public:
- STDMETHOD(OnFieldChange)(
- /* [in] */ IRowset* /* pRowset */,
- /* [in] */ HROW /* hRow */,
- /* [in] */ ULONG /* cColumns */,
- /* [size_is][in] */ ULONG /* rgColumns*/ [] ,
- /* [in] */ DBREASON /* eReason */,
- /* [in] */ DBEVENTPHASE /* ePhase */,
- /* [in] */ BOOL /* fCantDeny */)
- {
- ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnFieldChange"));
- }
- STDMETHOD(OnRowChange)(
- /* [in] */ IRowset* /* pRowset */,
- /* [in] */ ULONG /* cRows */,
- /* [size_is][in] */ const HROW /* rghRows*/ [] ,
- /* [in] */ DBREASON /* eReason */,
- /* [in] */ DBEVENTPHASE /* ePhase */,
- /* [in] */ BOOL /* fCantDeny */)
- {
- ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnRowChange"));
- }
- STDMETHOD(OnRowsetChange)(
- /* [in] */ IRowset* /* pRowset */,
- /* [in] */ DBREASON /* eReason */,
- /* [in] */ DBEVENTPHASE /* ePhase */,
- /* [in] */ BOOL /* fCantDeny*/)
- {
- ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnRowsetChange"));
- }
- };
-
- }; //namespace ATL
-
- #endif // __ATLDBCLI_H_
-