Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

787 lines
26 KiB

//---------------------------------------------------------------------------
// CursorBase.cpp : CursorBase implementation
//
// Copyright (c) 1996 Microsoft Corporation, All Rights Reserved
// Developed by Sheridan Software Systems, Inc.
//---------------------------------------------------------------------------
#include "stdafx.h"
#include "Notifier.h"
#include "RSColumn.h"
#include "RSSource.h"
#include "CursMain.h"
#include "CursBase.h"
#include "fastguid.h"
#include "resource.h"
SZTHISFILE
//=--------------------------------------------------------------------------=
// CVDCursorBase - Constructor
//
CVDCursorBase::CVDCursorBase()
{
m_ulCursorBindings = 0;
m_pCursorBindings = NULL;
m_fNeedVarData = FALSE;
m_cbRowLength = 0;
m_cbVarRowLength = 0;
#ifdef _DEBUG
g_cVDCursorBaseCreated++;
#endif
}
//=--------------------------------------------------------------------------=
// ~CVDCursorBase - Destructor
//
CVDCursorBase::~CVDCursorBase()
{
DestroyCursorBindings(&m_pCursorBindings, &m_ulCursorBindings);
#ifdef _DEBUG
g_cVDCursorBaseDestroyed++;
#endif
}
//=--------------------------------------------------------------------------=
// DestroyCursorBindings - Destroy cursor bindings and column identifer names
//
void CVDCursorBase::DestroyCursorBindings(CURSOR_DBCOLUMNBINDING** ppCursorBindings,
ULONG* pcBindings)
{
for (ULONG ulBind = 0; ulBind < *pcBindings; ulBind++)
{
CURSOR_DBCOLUMNID * pCursorColumnID = &(*ppCursorBindings)[ulBind].columnID;
if (pCursorColumnID->dwKind == CURSOR_DBCOLKIND_GUID_NAME || pCursorColumnID->dwKind == CURSOR_DBCOLKIND_NAME)
delete [] pCursorColumnID->lpdbsz;
}
delete [] *ppCursorBindings;
*ppCursorBindings = NULL;
*pcBindings = 0;
}
//=--------------------------------------------------------------------------=
// IsValidCursorType - Return TRUE if specified cursor data type is valid
//
BOOL CVDCursorBase::IsValidCursorType(DWORD dwCursorType)
{
BOOL fValid = FALSE;
switch (dwCursorType)
{
case CURSOR_DBTYPE_I2:
case CURSOR_DBTYPE_I4:
case CURSOR_DBTYPE_I8:
case CURSOR_DBTYPE_R4:
case CURSOR_DBTYPE_R8:
case CURSOR_DBTYPE_CY:
case CURSOR_DBTYPE_DATE:
case CURSOR_DBTYPE_FILETIME:
case CURSOR_DBTYPE_BOOL:
case CURSOR_DBTYPE_LPSTR:
case CURSOR_DBTYPE_LPWSTR:
case CURSOR_DBTYPE_BLOB:
case CURSOR_DBTYPE_UI2:
case CURSOR_DBTYPE_UI4:
case CURSOR_DBTYPE_UI8:
case CURSOR_DBTYPE_COLUMNID:
case CURSOR_DBTYPE_BYTES:
case CURSOR_DBTYPE_CHARS:
case CURSOR_DBTYPE_WCHARS:
case CURSOR_DBTYPE_ANYVARIANT:
case VT_VARIANT:
case VT_BSTR:
case VT_UI1:
case VT_I1:
fValid = TRUE;
break;
}
return fValid;
}
//=--------------------------------------------------------------------------=
// DoesCursorTypeNeedVarData - Return TRUE if specified cursor type needs
// variable length buffer
//
BOOL CVDCursorBase::DoesCursorTypeNeedVarData(DWORD dwCursorType)
{
BOOL fNeedsVarData = FALSE;
switch (dwCursorType)
{
case CURSOR_DBTYPE_BLOB:
case CURSOR_DBTYPE_LPSTR:
case CURSOR_DBTYPE_LPWSTR:
fNeedsVarData = TRUE;
break;
}
return fNeedsVarData;
}
//=--------------------------------------------------------------------------=
// GetCursorTypeLength - Get the size in bytes required by cursor data type
//
ULONG CVDCursorBase::GetCursorTypeLength(DWORD dwCursorType, ULONG cbMaxLen)
{
ULONG cbRequired = 0;
switch (dwCursorType)
{
case CURSOR_DBTYPE_I2:
case CURSOR_DBTYPE_UI2:
cbRequired = sizeof(short);
break;
case CURSOR_DBTYPE_I4:
case CURSOR_DBTYPE_UI4:
cbRequired = sizeof(long);
break;
case CURSOR_DBTYPE_I8:
case CURSOR_DBTYPE_UI8:
cbRequired = sizeof(LARGE_INTEGER);
break;
case CURSOR_DBTYPE_R4:
cbRequired = sizeof(float);
break;
case CURSOR_DBTYPE_R8:
cbRequired = sizeof(double);
break;
case CURSOR_DBTYPE_CY:
cbRequired = sizeof(CY);
break;
case CURSOR_DBTYPE_DATE:
cbRequired = sizeof(DATE);
break;
case CURSOR_DBTYPE_FILETIME:
cbRequired = sizeof(FILETIME);
break;
case CURSOR_DBTYPE_BOOL:
cbRequired = sizeof(VARIANT_BOOL);
break;
case CURSOR_DBTYPE_LPSTR:
cbRequired = sizeof(LPSTR);
break;
case CURSOR_DBTYPE_LPWSTR:
cbRequired = sizeof(LPWSTR);
break;
case CURSOR_DBTYPE_BLOB:
cbRequired = sizeof(BLOB);
break;
case CURSOR_DBTYPE_COLUMNID:
cbRequired = sizeof(CURSOR_DBCOLUMNID);
break;
case CURSOR_DBTYPE_BYTES:
cbRequired = cbMaxLen;
break;
case CURSOR_DBTYPE_CHARS:
cbRequired = cbMaxLen;
break;
case CURSOR_DBTYPE_WCHARS:
cbRequired = cbMaxLen;
break;
case CURSOR_DBTYPE_ANYVARIANT:
cbRequired = sizeof(CURSOR_DBVARIANT);
break;
case VT_VARIANT:
cbRequired = sizeof(VARIANT);
break;
case VT_I1:
case VT_UI1:
cbRequired = sizeof(BYTE);
break;
}
return cbRequired;
}
//=--------------------------------------------------------------------------=
// IsEqualCursorColumnID - Return TRUE if cursor column identifier are the same
//
BOOL CVDCursorBase::IsEqualCursorColumnID(const CURSOR_DBCOLUMNID& cursorColumnID1, const CURSOR_DBCOLUMNID& cursorColumnID2)
{
// first check to see if column identifers are the same kind
if (cursorColumnID1.dwKind != cursorColumnID1.dwKind)
return FALSE;
// then, check to see if they are equal
BOOL bResult = TRUE;
switch (cursorColumnID1.dwKind)
{
case CURSOR_DBCOLKIND_GUID_NAME:
if (!IsEqualGUID(cursorColumnID1.guid, cursorColumnID2.guid))
bResult = FALSE;
else if (lstrcmpW(cursorColumnID1.lpdbsz, cursorColumnID2.lpdbsz))
bResult = FALSE;
break;
case CURSOR_DBCOLKIND_GUID_NUMBER:
if (!IsEqualGUID(cursorColumnID1.guid, cursorColumnID2.guid))
bResult = FALSE;
else if (cursorColumnID1.lNumber != cursorColumnID2.lNumber)
bResult = FALSE;
break;
case CURSOR_DBCOLKIND_NAME:
if (lstrcmpW(cursorColumnID1.lpdbsz, cursorColumnID2.lpdbsz))
bResult = FALSE;
break;
}
return bResult;
}
//=--------------------------------------------------------------------------=
// GetCursorColumnIDNameLength - Get the size in bytes of possible name attached
// to the specified cursor column identifier
//
ULONG CVDCursorBase::GetCursorColumnIDNameLength(const CURSOR_DBCOLUMNID& cursorColumnID)
{
ULONG cbName = 0;
if (cursorColumnID.dwKind == CURSOR_DBCOLKIND_GUID_NAME || cursorColumnID.dwKind == CURSOR_DBCOLKIND_NAME)
cbName = (lstrlenW(cursorColumnID.lpdbsz) + 1) * sizeof(WCHAR);
return cbName;
}
//=--------------------------------------------------------------------------=
// ValidateCursorBindings - Validate cursor column bindings
//=--------------------------------------------------------------------------=
// This function makes sure the specified column bindings are acceptable
//
// Parameters:
// ulColumns - [in] the number available columns
// pColumns - [in] an array of available columns
// ulBindings - [in] the number of cursor column bindings
// pCursorBindings - [in] an array of cursor column bindings
// cbRequestedRowLength - [in] the requested number of bytes of inline
// memory in a single row of data
// dwFlags - [in] a flag that specifies whether to replace the
// existing column bindings or add to them
// pcbNewRowLength - [out] a pointer to memory in which to return
// the new number of bytes of inline memory
// in a single row of data for all bindings
// pcbNewRowLength - [out] a pointer to memory in which to return
// the new number of bytes of out-of-line memory
// in a single row of data for all bindings
//
// Output:
// HRESULT - S_OK if successful
// CURSOR_DB_E_BADBINDINFO bad binding information
// CURSOR_DB_E_COLUMNUNAVAILABLE columnID is not available
// CURSOR_DB_E_ROWTOOSHORT cbRequestedRowLength was less than the minumum (and not zero)
//
// Notes:
// This function also computes and returns the new fixed and variable buffer row length required
// by all the cursor bindings.
//
HRESULT CVDCursorBase::ValidateCursorBindings(ULONG ulColumns,
CVDRowsetColumn * pColumns,
ULONG ulBindings,
CURSOR_DBCOLUMNBINDING * pCursorBindings,
ULONG cbRequestedRowLength,
DWORD dwFlags,
ULONG * pcbNewRowLength,
ULONG * pcbNewVarRowLength)
{
DWORD cbMaxLength;
DWORD dwCursorType;
BOOL fColumnIDAvailable;
CVDRowsetColumn * pColumn;
ULONG cbRequiredRowLength = 0;
ULONG cbRequiredVarRowLength = 0;
CURSOR_DBCOLUMNBINDING * pBinding = pCursorBindings;
// iterate through bindings
for (ULONG ulBind = 0; ulBind < ulBindings; ulBind++)
{
// make sure column identifier is available
fColumnIDAvailable = FALSE;
pColumn = pColumns;
for (ULONG ulCol = 0; ulCol < ulColumns && !fColumnIDAvailable; ulCol++)
{
if (IsEqualCursorColumnID(pBinding->columnID, pColumn->GetCursorColumnID()))
{
cbMaxLength = pColumn->GetMaxLength();
dwCursorType = pColumn->GetCursorType();
fColumnIDAvailable = TRUE;
}
pColumn++;
}
if (!fColumnIDAvailable)
{
VDSetErrorInfo(IDS_ERR_COLUMNUNAVAILABLE, IID_ICursor, m_pResourceDLL);
return CURSOR_DB_E_COLUMNUNAVAILABLE;
}
// make sure caller supplied a maximum length if a default binding was specified
// for the cursor types CURSOR_DBTYPE_CHARS, CURSOR_DBTYPE_WCHARS or CURSOR_DBTYPE_BYTES
if (pBinding->cbMaxLen == CURSOR_DB_NOMAXLENGTH &&
pBinding->dwBinding == CURSOR_DBBINDING_DEFAULT)
{
if (pBinding->dwDataType == CURSOR_DBTYPE_CHARS ||
pBinding->dwDataType == CURSOR_DBTYPE_WCHARS ||
pBinding->dwDataType == CURSOR_DBTYPE_BYTES)
{
VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
return CURSOR_DB_E_BADBINDINFO;
}
}
// check binding bit mask for possible values
if (pBinding->dwBinding != CURSOR_DBBINDING_DEFAULT &&
pBinding->dwBinding != CURSOR_DBBINDING_VARIANT &&
pBinding->dwBinding != CURSOR_DBBINDING_ENTRYID &&
pBinding->dwBinding != (CURSOR_DBBINDING_VARIANT | CURSOR_DBBINDING_ENTRYID))
{
VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
return CURSOR_DB_E_BADBINDINFO;
}
// check for valid cursor type
if (!IsValidCursorType(pBinding->dwDataType))
{
VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
return CURSOR_DB_E_BADBINDINFO;
}
// if a variant binding was specified make sure the cursor type is not CURSOR_DBTYPE_CHARS,
// CURSOR_DBTYPE_WCHARS or CURSOR_DBTYPE_BYTES
if (pBinding->dwBinding & CURSOR_DBBINDING_VARIANT)
{
if (pBinding->dwDataType == CURSOR_DBTYPE_CHARS ||
pBinding->dwDataType == CURSOR_DBTYPE_WCHARS ||
pBinding->dwDataType == CURSOR_DBTYPE_BYTES)
{
VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
return CURSOR_DB_E_BADBINDINFO;
}
}
// if its not a variant binding make sure the cursor type is not CURSOR_DBTYPE_ANYVARIANT
if (!(pBinding->dwBinding & CURSOR_DBBINDING_VARIANT) && pBinding->dwDataType == CURSOR_DBTYPE_ANYVARIANT)
{
VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursor, m_pResourceDLL);
return CURSOR_DB_E_BADBINDINFO;
}
// calulate row length required by data field
if (!(pBinding->dwBinding & CURSOR_DBBINDING_VARIANT))
cbRequiredRowLength += GetCursorTypeLength(pBinding->dwDataType, pBinding->cbMaxLen);
else
cbRequiredRowLength += sizeof(CURSOR_DBVARIANT);
// calulate row length required by variable data length field
if (pBinding->obVarDataLen != CURSOR_DB_NOVALUE)
cbRequiredRowLength += sizeof(ULONG);
// calulate row length required by information field
if (pBinding->obInfo != CURSOR_DB_NOVALUE)
cbRequiredRowLength += sizeof(DWORD);
// calulate variable row length required by data field
if (!(pBinding->dwBinding & CURSOR_DBBINDING_VARIANT))
{
if (DoesCursorTypeNeedVarData(pBinding->dwDataType))
{
if (pBinding->cbMaxLen != CURSOR_DB_NOMAXLENGTH)
cbRequiredVarRowLength += pBinding->cbMaxLen;
else
cbRequiredVarRowLength += cbMaxLength;
}
}
else // variant binding
{
if (DoesCursorTypeNeedVarData(pBinding->dwDataType))
{
if (pBinding->cbMaxLen != CURSOR_DB_NOMAXLENGTH)
cbRequiredVarRowLength += pBinding->cbMaxLen;
else
cbRequiredVarRowLength += cbMaxLength;
}
if (pBinding->dwDataType == CURSOR_DBTYPE_COLUMNID)
cbRequiredVarRowLength += sizeof(CURSOR_DBCOLUMNID);
}
pBinding++;
}
// if we're replacing bindings reset row lengths
if (dwFlags == CURSOR_DBCOLUMNBINDOPTS_REPLACE)
{
*pcbNewRowLength = 0;
*pcbNewVarRowLength = 0;
}
else // if we're adding bindings set to current row lengths
{
*pcbNewRowLength = m_cbRowLength;
*pcbNewVarRowLength = m_cbVarRowLength;
}
// if no row length was requested, use required row length
if (!cbRequestedRowLength)
{
*pcbNewRowLength += cbRequiredRowLength;
}
else // make sure row length is large enough
{
if (cbRequestedRowLength < *pcbNewRowLength + cbRequiredRowLength)
{
VDSetErrorInfo(IDS_ERR_ROWTOOSHORT, IID_ICursor, m_pResourceDLL);
return CURSOR_DB_E_ROWTOOSHORT;
}
// use requested row length
*pcbNewRowLength += cbRequestedRowLength;
}
// calculate required variable row length
*pcbNewVarRowLength += cbRequiredVarRowLength;
return S_OK;
}
//=--------------------------------------------------------------------------=
// DoCursorBindingsNeedVarData - Return TRUE if current cursor column bindings
// need variable length buffer
//
BOOL CVDCursorBase::DoCursorBindingsNeedVarData()
{
BOOL fNeedVarData = FALSE;
CURSOR_DBCOLUMNBINDING * pCursorBinding = m_pCursorBindings;
for (ULONG ulBind = 0; ulBind < m_ulCursorBindings && !fNeedVarData; ulBind++)
{
if (DoesCursorTypeNeedVarData(pCursorBinding->dwDataType))
fNeedVarData = TRUE;
pCursorBinding++;
}
return fNeedVarData;
}
//=--------------------------------------------------------------------------=
// Validate fetch params
//=--------------------------------------------------------------------------=
//
// Parameters:
// pFetchParams - [in] ptr to the CURSOR_DBFETCHROWS structure
// riid - [in] guid of calling interface (used for error generation)
//
// Output:
// HRESULT - S_OK if pFetchParams valid
// CURSOR_DB_E_BADFETCHINFO if pFetchParams invalid
//
//
HRESULT CVDCursorBase::ValidateFetchParams(CURSOR_DBFETCHROWS *pFetchParams, REFIID riid)
{
if (!pFetchParams)
{
VDSetErrorInfo(IDS_ERR_INVALIDARG, riid, m_pResourceDLL);
return E_INVALIDARG;
}
// init out parameter
pFetchParams->cRowsReturned = 0;
// return if caller didn't ask for any rows
if (!pFetchParams->cRowsRequested)
return S_OK;
HRESULT hr = S_OK;
// make sure fetch flags has only valid values
if (pFetchParams->dwFlags != CURSOR_DBROWFETCH_DEFAULT &&
pFetchParams->dwFlags != CURSOR_DBROWFETCH_CALLEEALLOCATES &&
pFetchParams->dwFlags != CURSOR_DBROWFETCH_FORCEREFRESH &&
pFetchParams->dwFlags != (CURSOR_DBROWFETCH_CALLEEALLOCATES | CURSOR_DBROWFETCH_FORCEREFRESH))
hr = CURSOR_DB_E_BADFETCHINFO;
// if memory was caller allocated, make sure caller supplied data pointer
if (!(pFetchParams->dwFlags & CURSOR_DBROWFETCH_CALLEEALLOCATES) && !pFetchParams->pData)
hr = CURSOR_DB_E_BADFETCHINFO;
// if memory was caller allocated, make sure caller supplied var-data pointer and size if needed
if (!(pFetchParams->dwFlags & CURSOR_DBROWFETCH_CALLEEALLOCATES) && m_fNeedVarData &&
(!pFetchParams->pVarData || !pFetchParams->cbVarData))
hr = CURSOR_DB_E_BADFETCHINFO;
if (FAILED(hr))
VDSetErrorInfo(IDS_ERR_BADFETCHINFO, riid, m_pResourceDLL);
return hr;
}
//=--------------------------------------------------------------------------=
// IUnknown methods implemented
//=--------------------------------------------------------------------------=
//=--------------------------------------------------------------------------=
// IUnknown QueryInterface
//
HRESULT CVDCursorBase::QueryInterface(REFIID riid, void **ppvObjOut)
{
ASSERT_POINTER(ppvObjOut, IUnknown*)
if (!ppvObjOut)
return E_INVALIDARG;
*ppvObjOut = NULL;
switch (riid.Data1)
{
QI_INTERFACE_SUPPORTED((ICursor*)this, IUnknown);
QI_INTERFACE_SUPPORTED(this, ICursor);
QI_INTERFACE_SUPPORTED(this, ICursorMove);
QI_INTERFACE_SUPPORTED_IF(this, ICursorScroll, SupportsScroll());
QI_INTERFACE_SUPPORTED(this, ISupportErrorInfo);
}
if (NULL == *ppvObjOut)
return E_NOINTERFACE;
AddRef();
return S_OK;
}
//=--------------------------------------------------------------------------=
// IUnknown AddRef (Notifier and MetadataCursor maintain reference count)
//
ULONG CVDCursorBase::AddRef(void)
{
return (ULONG)E_NOTIMPL;
}
//=--------------------------------------------------------------------------=
// IUnknown Release (Notifier and MetadataCursor maintain reference count)
//
ULONG CVDCursorBase::Release(void)
{
return (ULONG)E_NOTIMPL;
}
//=--------------------------------------------------------------------------=
// ICursor methods implemented
//=--------------------------------------------------------------------------=
// ICursor SetBindings
//=--------------------------------------------------------------------------=
// Replaces the existing column bindings or adds new column bindings to the
// existing ones
//
// Parameters:
// cCol - [in] the number of columns to bind
// rgBoundColumns - [in] an array of column bindings, one for each
// column for which data is to be returned
// cbRowLength - [in] the number of bytes of inline memory in a
// single row of data
// dwFlags - [in] a flag that specifies whether to replace the
// existing column bindings or add to them
//
// Output:
// HRESULT - S_OK if successful
// E_OUTOFMEMORY not enough memory
//
// Notes:
// Parameter validation is performed by derived classes
//
HRESULT CVDCursorBase::SetBindings(ULONG cCol, CURSOR_DBCOLUMNBINDING rgBoundColumns[], ULONG cbRowLength, DWORD dwFlags)
{
// reset flag
m_fNeedVarData = FALSE;
// if we should replace, then first destroy existing bindings
if (dwFlags == CURSOR_DBCOLUMNBINDOPTS_REPLACE)
DestroyCursorBindings(&m_pCursorBindings, &m_ulCursorBindings);
// if no new bindings are supplied, we're done
if (!cCol)
return S_OK;
// create new storage
CURSOR_DBCOLUMNBINDING * pCursorBindings = new CURSOR_DBCOLUMNBINDING[m_ulCursorBindings + cCol];
if (!pCursorBindings)
{
VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
return E_OUTOFMEMORY;
}
// if we have exsiting bindings, then copy them over
if (m_pCursorBindings)
memcpy(pCursorBindings, m_pCursorBindings, m_ulCursorBindings * sizeof(CURSOR_DBCOLUMNBINDING));
// then append new bindings directly,
memcpy(pCursorBindings + m_ulCursorBindings, rgBoundColumns, cCol * sizeof(CURSOR_DBCOLUMNBINDING));
// and adjust possible cursor column identifier names in new bindings
for (ULONG ulBind = m_ulCursorBindings; ulBind < m_ulCursorBindings + cCol; ulBind++)
{
CURSOR_DBCOLUMNID * pCursorColumnID = &pCursorBindings[ulBind].columnID;
if (pCursorColumnID->dwKind == CURSOR_DBCOLKIND_GUID_NAME || pCursorColumnID->dwKind == CURSOR_DBCOLKIND_NAME)
{
const int nLength = lstrlenW(pCursorColumnID->lpdbsz);
WCHAR * pwszName = new WCHAR[nLength + 1];
if (!pwszName)
{
DestroyCursorBindings(&pCursorBindings, &ulBind);
delete [] m_pCursorBindings;
m_ulCursorBindings = 0;
VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
return E_OUTOFMEMORY;
}
memcpy(pwszName, pCursorColumnID->lpdbsz, (nLength + 1) * sizeof(WCHAR));
pCursorColumnID->lpdbsz = pwszName;
}
}
m_ulCursorBindings += cCol;
// delete previous storage
// any existing bindings will have been copied over into
delete [] m_pCursorBindings;
m_pCursorBindings = pCursorBindings;
// determine if new bindings need variable length buffer
m_fNeedVarData = DoCursorBindingsNeedVarData();
return S_OK;
}
//=--------------------------------------------------------------------------=
// ICursor GetBindings
//=--------------------------------------------------------------------------=
// Returns the current column bindings
//
// Parameters:
// pcCol - [out] a pointer to memory in which to return the
// number of bound columns
// prgBoundColumns - [out] a pointer to memory in which to return a
// pointer to an array containing the current
// column bindings (callee allocated)
// pcbRowLength - [out] a pointer to memory in which to return the
// number of bytes of inline memory in a single
// row
//
// Output:
// HRESULT - S_OK if successful
// E_OUTOFMEMORY not enough memory
//
// Notes:
//
HRESULT CVDCursorBase::GetBindings(ULONG *pcCol,
CURSOR_DBCOLUMNBINDING *prgBoundColumns[],
ULONG *pcbRowLength)
{
ASSERT_NULL_OR_POINTER(pcCol, ULONG)
ASSERT_NULL_OR_POINTER(prgBoundColumns, CURSOR_DBCOLUMNBINDING)
ASSERT_NULL_OR_POINTER(pcbRowLength, ULONG)
// init out parameters
if (pcCol)
*pcCol = 0;
if (prgBoundColumns)
*prgBoundColumns = NULL;
if (pcbRowLength)
*pcbRowLength = 0;
// return column bindings
if (prgBoundColumns && m_ulCursorBindings)
{
// calculate size of bindings
ULONG cbBindings = m_ulCursorBindings * sizeof(CURSOR_DBCOLUMNBINDING);
// calculate extra space needed for names in column identifers
ULONG cbNames = 0;
for (ULONG ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
cbNames += GetCursorColumnIDNameLength(m_pCursorBindings[ulBind].columnID);
// allocate memory for bindings and names
CURSOR_DBCOLUMNBINDING * pCursorBindings = (CURSOR_DBCOLUMNBINDING*)g_pMalloc->Alloc(cbBindings + cbNames);
if (!pCursorBindings)
{
VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
return E_OUTOFMEMORY;
}
// copy bindings directly
memcpy(pCursorBindings, m_pCursorBindings, cbBindings);
// adjust column identifier names
WCHAR * pwszName = (WCHAR*)(pCursorBindings + m_ulCursorBindings);
for (ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
{
CURSOR_DBCOLUMNID * pCursorColumnID = &pCursorBindings[ulBind].columnID;
if (pCursorColumnID->dwKind == CURSOR_DBCOLKIND_GUID_NAME || pCursorColumnID->dwKind == CURSOR_DBCOLKIND_NAME)
{
const int nLength = lstrlenW(pCursorColumnID->lpdbsz);
memcpy(pwszName, pCursorColumnID->lpdbsz, (nLength + 1) * sizeof(WCHAR));
pCursorColumnID->lpdbsz = pwszName;
pwszName += nLength + 1;
}
}
*prgBoundColumns = pCursorBindings;
// sanity check
ASSERT_((BYTE*)pwszName == ((BYTE*)pCursorBindings) + cbBindings + cbNames);
}
// return bound column count
if (pcCol)
*pcCol = m_ulCursorBindings;
// return row length
if (pcbRowLength)
*pcbRowLength = m_cbRowLength;
return S_OK;
}