|
|
//---------------------------------------------------------------------------
// 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; }
|