📄 atldbcli.h
字号:
// 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_
#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(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;
HRESULT hr = pUnk->QueryInterface(&spSupportErrorInfo);
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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -