|
|
//-----------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: crowprov.cxx
//
// Contents: IProvider implementation for ADSI rowsets
//
// Functions:
//
// Notes:
//
//
// History: 07/10/96 | RenatoB | Created, lifted most from EricJ code
//-----------------------------------------------------------------------------
// Includes
#include "oleds.hxx"
HRESULT PackLargeInteger( LARGE_INTEGER *plargeint, PVARIANT pVarDestObject );
HRESULT PackDNWithBinary( PADS_DN_WITH_BINARY pDNWithBinary, PVARIANT pVarDestObject );
HRESULT PackDNWithString( PADS_DN_WITH_STRING pDNWithString, PVARIANT pVarDestObject );
//+---------------------------------------------------------------------------
//
// Function: CreateRowProvider
//
// Synopsis: @mfunc Creates and initializes a Row provider .
//
//----------------------------------------------------------------------------
HRESULT CRowProvider::CreateRowProvider( IDirectorySearch * pDSSearch, LPWSTR pszFilter, LPWSTR * ppszAttrs, DWORD cAttrs, DBORDINAL cColumns, // count of the rowset's columns
DBCOLUMNINFO * rgInfo, // array of cColumns DBCOLUMNINFO's
OLECHAR* pStringsBuffer, // the names of the columns are here
REFIID riid, BOOL * pMultiValued, BOOL fADSPathPresent, CCredentials * pCredentials, void ** ppvObj // the created Row provider
) { HRESULT hr; CRowProvider * pRowProvider = NULL;
if( ppvObj ) *ppvObj = NULL; else BAIL_ON_FAILURE( hr = E_INVALIDARG );
pRowProvider = new CRowProvider(); if( pRowProvider == NULL ) BAIL_ON_FAILURE( hr = E_OUTOFMEMORY );
//
//initialize rowprovider with the search filter and the columnsinfo
//
hr = pRowProvider->FInit( pDSSearch, pszFilter, ppszAttrs, cAttrs, cColumns, rgInfo, pStringsBuffer, pMultiValued, fADSPathPresent, pCredentials );
if( FAILED(hr) ) { delete pRowProvider; BAIL_ON_FAILURE( hr ); }
//
// This interface pointer is embedded in the pRowProvider.
//
pDSSearch = NULL;
hr = pRowProvider->QueryInterface( riid, ppvObj); if( FAILED(hr) ) { delete pRowProvider; BAIL_ON_FAILURE( hr ); }
pRowProvider->Release();
RRETURN( S_OK );
error:
if( pDSSearch ) pDSSearch->Release();
RRETURN( hr ); }
//+---------------------------------------------------------------------------
//
// Function: CRowProvider::CRowProvider
//
//----------------------------------------------------------------------------
CRowProvider::CRowProvider() : _pMalloc (NULL), _cColumns (0), _ColInfo (NULL), _pwchBuf (NULL), _hSearchHandle (NULL), _pdbSearchCol (NULL), _pDSSearch (NULL), _pMultiValued (NULL), _fADSPathPresent (FALSE), _iAdsPathIndex (0), _pCredentials (NULL)
{ }
//+---------------------------------------------------------------------------
//
// Function: CRowProvider::~CRowProvider
//
//----------------------------------------------------------------------------
CRowProvider::~CRowProvider() { ULONG i;
if( _hSearchHandle != NULL ) _pDSSearch->CloseSearchHandle(_hSearchHandle);
if( _pDSSearch != NULL ) _pDSSearch->Release();
// Release the memory allocated for columns and ColumnsInfo
if (_pMalloc != NULL) { if( _pdbSearchCol != NULL ) { _pMalloc->Free((void*)_pdbSearchCol); }
if( _ColInfo != NULL ) _pMalloc->Free(_ColInfo);
if( _pwchBuf != NULL ) _pMalloc->Free(_pwchBuf);
_pMalloc->Release(); }
if( _pMultiValued ) { FreeADsMem(_pMultiValued); }
if( _pCredentials ) delete _pCredentials; };
//+---------------------------------------------------------------------------
//
// Function: CRowProvider::Finit
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowProvider::FInit( IDirectorySearch * pDSSearch, LPWSTR pszFilter, LPWSTR * ppszAttrs, DWORD cAttrs, DBORDINAL cColumns, DBCOLUMNINFO * rgInfo, OLECHAR * pStringsBuffer, BOOL * pMultiValued, BOOL fADSPathPresent, CCredentials * pCredentials) { HRESULT hr; ULONG i; ULONG cChars, cCharDispl;
//
// Asserts
//
ADsAssert(cColumns); ADsAssert(rgInfo); ADsAssert(pDSSearch);
_cColumns= cColumns;
hr = CoGetMalloc(MEMCTX_TASK, &_pMalloc); BAIL_ON_FAILURE( hr );
_ColInfo = (DBCOLUMNINFO*)_pMalloc->Alloc((size_t)(cColumns *sizeof(DBCOLUMNINFO))); if( _ColInfo == NULL ) BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
memcpy(_ColInfo, rgInfo, (size_t)(cColumns * sizeof(DBCOLUMNINFO)));
cChars = _pMalloc->GetSize(pStringsBuffer); _pwchBuf = (WCHAR*)_pMalloc->Alloc(cChars); if( _pwchBuf == NULL ) BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
memcpy(_pwchBuf, (void*)pStringsBuffer , cChars);
for (i=0; i<_cColumns; i++) { if( rgInfo[i].pwszName ) { cCharDispl = (ULONG)(rgInfo[i].pwszName - pStringsBuffer); _ColInfo[i].pwszName = _pwchBuf + cCharDispl; _ColInfo[i].columnid.uName.pwszName = _pwchBuf + cCharDispl; } }
// We have adspath at the end of the attribute list.
_fADSPathPresent = fADSPathPresent ;
//Store credentials if non-NULL.
if( pCredentials ) { //We don't expect that _pCredentials is already non-NULL
ADsAssert(_pCredentials == NULL); _pCredentials = new CCredentials(*pCredentials); if( !_pCredentials ) BAIL_ON_FAILURE( hr=E_OUTOFMEMORY ); }
if( _fADSPathPresent == FALSE ) cAttrs++;
//
// Create _pdbSearchCol, a member containing an array
// of DB_SEARCH_COLUMN.
// Reason for this is that trowset.cpp sometimes asks
// for GetColumn twice: one to get the size of the column
// and one to get the data.
// Since OLEDP copies data, we do not want to have two copies
// around
//
_pdbSearchCol = (PDB_SEARCH_COLUMN)_pMalloc->Alloc((ULONG)((cColumns + 1)*sizeof(DB_SEARCH_COLUMN))); if( _pdbSearchCol == NULL ) { hr = E_OUTOFMEMORY; goto error; }
_pDSSearch = pDSSearch;
hr = _pDSSearch->ExecuteSearch( pszFilter, ppszAttrs, cAttrs, &_hSearchHandle ); BAIL_ON_FAILURE( hr );
_pMultiValued = pMultiValued;
RRETURN( hr );
error:
if( _pMalloc != NULL ) { if( _pdbSearchCol != NULL ) { _pMalloc->Free((void*)_pdbSearchCol); _pdbSearchCol= NULL; }; if( _ColInfo != NULL ) { _pMalloc->Free(_ColInfo); _ColInfo = NULL; }
if( _pwchBuf != NULL ) { _pMalloc->Free(_pwchBuf); _pwchBuf = NULL; }
_pMalloc->Release(); _pMalloc = NULL; };
if (_hSearchHandle != NULL) _pDSSearch->CloseSearchHandle(_hSearchHandle);
_hSearchHandle = NULL;
_pDSSearch = NULL;
RRETURN( hr ); }
//+---------------------------------------------------------------------------
//
// Function: CRowProvider::QueryInterface
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowProvider::QueryInterface( REFIID riid, LPVOID * ppv) { if( !ppv ) RRETURN( E_INVALIDARG );
if( riid == IID_IUnknown || riid == IID_IRowProvider ) *ppv = (IRowProvider FAR *) this; else if( riid == IID_IColumnsInfo ) *ppv = (IColumnsInfo FAR *) this; else { *ppv = NULL; return E_NOINTERFACE; }
AddRef(); RRETURN( S_OK ); }
//-----------------------------------------------------------------------------
//
// Function: CRowProvider::NextRow
//
// Synopsis: Advance to the next row.
//
// Called by: Client.
// Called when: To advance to next row.
// This sets the "current" row.
// Initially the "current" row is prior to the first actual row.
// (Which means This must be called prior to the first GetColumn call.)
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowProvider::NextRow() { HRESULT hr; ULONG i; DWORD dwType, dwExtError = ERROR_SUCCESS; VARTYPE vType = VT_NULL; const int ERROR_BUF_SIZE = 512; const int NAME_BUF_SIZE = 128; WCHAR ErrorBuf[ERROR_BUF_SIZE]; WCHAR NameBuf[NAME_BUF_SIZE];
do { // Clear the ADSI extended error, so that after the call to GetNextRow,
// we can safely check if an extended error was set.
ADsSetLastError(ERROR_SUCCESS, NULL, NULL); dwExtError = ERROR_SUCCESS;
//
// read the next row
//
hr = _pDSSearch->GetNextRow( _hSearchHandle );
// we should treat SIZE_LIMIT_EXCEEDED error message as
// S_ADS_NOMORE_ROWS
// in the future, we might want to return this error message
// to the user under non-paged search situation
if (LIMIT_EXCEEDED_ERROR(hr)) hr = S_ADS_NOMORE_ROWS; BAIL_ON_FAILURE( hr );
if (hr == S_ADS_NOMORE_ROWS) { // check if more results are likely (pagedTimeLimit search). If so,
// we will keep trying till a row is obtained.
hr = ADsGetLastError(&dwExtError, ErrorBuf, ERROR_BUF_SIZE, NameBuf, NAME_BUF_SIZE); BAIL_ON_FAILURE(hr);
if (dwExtError != ERROR_MORE_DATA) // we really have no more data
RRETURN(DB_S_ENDOFROWSET); } } while(ERROR_MORE_DATA == dwExtError);
//
//read all the columnsinto _pdbSearchCol leaving the bookmark column
//
for (i=1; i<_cColumns; i++) {
hr = _pDSSearch->GetColumn( _hSearchHandle, _ColInfo[i].pwszName, &(_pdbSearchCol[i].adsColumn) ); if (FAILED(hr) && hr != E_ADS_COLUMN_NOT_SET) goto error;
if (hr == E_ADS_COLUMN_NOT_SET || _pdbSearchCol[i].adsColumn.dwNumValues == 0) {
_pdbSearchCol[i].dwStatus = DBSTATUS_S_ISNULL; _pdbSearchCol[i].dwType = DBTYPE_EMPTY; _pdbSearchCol[i].dwLength = 0; hr = S_OK;
} else if (_ColInfo[i].wType == (DBTYPE_VARIANT | DBTYPE_BYREF)) { _pdbSearchCol[i].dwStatus = DBSTATUS_S_OK; _pdbSearchCol[i].dwType = _ColInfo[i].wType; _pdbSearchCol[i].dwLength = sizeof(VARIANT); } else if ((ULONG) _pdbSearchCol[i].adsColumn.dwADsType >= g_cMapADsTypeToDBType || g_MapADsTypeToDBType[_pdbSearchCol[i].adsColumn.dwADsType].wType == DBTYPE_NULL) { _pdbSearchCol[i].dwStatus = DBSTATUS_E_CANTCONVERTVALUE; _pdbSearchCol[i].dwType = DBTYPE_EMPTY; _pdbSearchCol[i].dwLength = 0; } else { _pdbSearchCol[i].dwStatus = DBSTATUS_S_OK; _pdbSearchCol[i].dwType = g_MapADsTypeToDBType[_pdbSearchCol[i].adsColumn.dwADsType].wType;
switch (_pdbSearchCol[i].dwType & ~DBTYPE_BYREF) { case DBTYPE_WSTR: _pdbSearchCol[i].dwLength = (wcslen( _pdbSearchCol[i].adsColumn.pADsValues[0].CaseIgnoreString)) * sizeof (WCHAR); break;
case DBTYPE_BYTES: if(_pdbSearchCol[i].adsColumn.dwADsType == ADSTYPE_OCTET_STRING) _pdbSearchCol[i].dwLength = _pdbSearchCol[i].adsColumn.pADsValues[0].OctetString.dwLength; else if(_pdbSearchCol[i].adsColumn.dwADsType == ADSTYPE_NT_SECURITY_DESCRIPTOR) _pdbSearchCol[i].dwLength = _pdbSearchCol[i].adsColumn.pADsValues[0].SecurityDescriptor.dwLength; else if(_pdbSearchCol[i].adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) _pdbSearchCol[i].dwLength = _pdbSearchCol[i].adsColumn.pADsValues[0].ProviderSpecific.dwLength;
break;
default: _pdbSearchCol[i].dwLength = g_MapADsTypeToDBType[_pdbSearchCol[i].adsColumn.dwADsType].ulSize; } } }
if ((FALSE == _fADSPathPresent)) { hr = _pDSSearch->GetColumn( _hSearchHandle, L"AdsPath", &(_pdbSearchCol[i].adsColumn) ); if FAILED(hr) goto error; }
RRETURN(hr);
error: RRETURN(hr); }
//-----------------------------------------------------------------------------
//
// Function: CRowProvider::GetColumn
//
// Synopsis: @mfunc Get a column value.
//
// We only provide a ptr to the value -- retained in our memory
// space.
//
// Called by: Client.
// Called when: After NextRow, once for each column.
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowProvider::GetColumn( ULONG iCol, DBSTATUS *pdbStatus, ULONG *pdwLength, BYTE *pbData ) {
DBTYPE columnType = 0; DBSTATUS dbStatus_temp = 0; BOOL is_Ref = FALSE; HRESULT hr = S_OK;
ADsAssert( 1 <= iCol && iCol <= _cColumns );
//
// Note that the caller gives us a ptr to where to put the data.
// We can fill in dwStatus, dwLength.
// For pbData, we assume this is a ptr to where we are to write our ptr.
//
columnType = _ColInfo[iCol].wType; if ((columnType & DBTYPE_ARRAY) || (columnType & DBTYPE_VECTOR) ) { if (pdbStatus != NULL) *pdbStatus= DBSTATUS_E_UNAVAILABLE;
if (pdwLength != NULL) *pdwLength = 0;
RRETURN(DB_S_ERRORSOCCURRED); }
if (pdwLength!= NULL) *pdwLength = _pdbSearchCol[iCol].dwLength;
dbStatus_temp = _pdbSearchCol[iCol].dwStatus;
if (columnType & DBTYPE_BYREF) is_Ref = TRUE;
columnType &= (~DBTYPE_BYREF);
if (pbData != NULL && dbStatus_temp == DBSTATUS_S_OK) { switch (columnType) { case DBTYPE_BOOL: * (VARIANT_BOOL*) pbData = _pdbSearchCol[iCol].adsColumn.pADsValues[0].Boolean ? VARIANT_TRUE: VARIANT_FALSE; break; case DBTYPE_I4: * (DWORD*) pbData = _pdbSearchCol[iCol].adsColumn.pADsValues[0].Integer; break; case DBTYPE_WSTR: *(WCHAR**)pbData = _pdbSearchCol[iCol].adsColumn.pADsValues[0].CaseIgnoreString; break; case DBTYPE_BYTES: if(_pdbSearchCol[iCol].adsColumn.dwADsType == ADSTYPE_OCTET_STRING) *(BYTE**)pbData = _pdbSearchCol[iCol].adsColumn.pADsValues[0].OctetString.lpValue; else if(_pdbSearchCol[iCol].adsColumn.dwADsType == ADSTYPE_NT_SECURITY_DESCRIPTOR) *(BYTE**)pbData = _pdbSearchCol[iCol].adsColumn.pADsValues[0].SecurityDescriptor.lpValue;
else if(_pdbSearchCol[iCol].adsColumn.dwADsType == ADSTYPE_PROV_SPECIFIC) *(BYTE**)pbData = _pdbSearchCol[iCol].adsColumn.pADsValues[0].ProviderSpecific.lpValue;
break; case DBTYPE_DATE: { double date = 0; hr = SystemTimeToVariantTime( &_pdbSearchCol[iCol].adsColumn.pADsValues[0].UTCTime, &date); if( FAILED(hr) ) if (pdbStatus != NULL) *pdbStatus= DBSTATUS_E_CANTCONVERTVALUE;
BAIL_ON_FAILURE(hr); *(double*)pbData = date; break; } case DBTYPE_VARIANT: if (_pMultiValued[iCol] == FALSE) { PVARIANT pVariant = (PVARIANT) AllocADsMem(sizeof(VARIANT)); if (!pVariant) { if (pdbStatus != NULL) *pdbStatus= DBSTATUS_E_CANTCONVERTVALUE; hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); }
if(_pdbSearchCol[iCol].adsColumn.dwADsType == ADSTYPE_LARGE_INTEGER) hr = PackLargeInteger( &_pdbSearchCol[iCol].adsColumn.pADsValues[0].LargeInteger, pVariant); else if(_pdbSearchCol[iCol].adsColumn.dwADsType == ADSTYPE_DN_WITH_BINARY) hr = PackDNWithBinary(_pdbSearchCol[iCol].adsColumn.pADsValues[0].pDNWithBinary, pVariant);
else if(_pdbSearchCol[iCol].adsColumn.dwADsType == ADSTYPE_DN_WITH_STRING) hr = PackDNWithString(_pdbSearchCol[iCol].adsColumn.pADsValues[0].pDNWithString, pVariant);
if( FAILED(hr) ) if (pdbStatus != NULL) *pdbStatus= DBSTATUS_E_CANTCONVERTVALUE; BAIL_ON_FAILURE(hr); *((PVARIANT*)pbData) = pVariant; } else { hr = CopyADs2VariantArray( &_pdbSearchCol[iCol].adsColumn, (PVARIANT *) pbData ); if (hr == E_ADS_CANT_CONVERT_DATATYPE) { dbStatus_temp= DBSTATUS_E_UNAVAILABLE; break; } if( FAILED(hr) ) if (pdbStatus != NULL) *pdbStatus= DBSTATUS_E_CANTCONVERTVALUE; BAIL_ON_FAILURE(hr); } break;
default: dbStatus_temp= DBSTATUS_E_UNAVAILABLE; break; }; }; if (pdbStatus == 0) RRETURN(S_OK);
if (pdbStatus != NULL)
*pdbStatus = dbStatus_temp;
if (dbStatus_temp == DBSTATUS_S_OK || dbStatus_temp == DBSTATUS_S_ISNULL) RRETURN(S_OK); else RRETURN(DB_S_ERRORSOCCURRED);
error: RRETURN(hr); }
HRESULT CRowProvider::GetIndex( IColumnsInfo* pColumnsInfo, LPWSTR lpwszColName, int& iIndex ) { #if (!defined(BUILD_FOR_NT40))
HRESULT hr = S_OK; int iColumn; DBCOLUMNINFO* pColumnInfo = NULL; DBORDINAL cColumns = 0; OLECHAR* pStringsBuffer = NULL;
iIndex = 0; hr = pColumnsInfo->GetColumnInfo(&cColumns, &pColumnInfo, &pStringsBuffer); BAIL_ON_FAILURE(hr);
for(iColumn = 0; iColumn < cColumns; iColumn++) { if(pColumnInfo[iColumn].pwszName == NULL || lpwszColName == NULL) continue;
if(!_wcsicmp(pColumnInfo[iColumn].pwszName, lpwszColName)) { iIndex = iColumn; break; } }
if (pColumnInfo) _pMalloc->Free((void*)pColumnInfo); if (pStringsBuffer) _pMalloc->Free((void*)pStringsBuffer);
RRETURN(S_OK);
error: if (pColumnInfo) _pMalloc->Free((void*)pColumnInfo); if (pStringsBuffer) _pMalloc->Free((void*)pStringsBuffer); RRETURN(hr); #else
RRETURN(E_FAIL); #endif
}
STDMETHODIMP CRowProvider::GetURLFromHROW( HROW hRow, LPOLESTR *ppwszURL, IRowset* pRowset ) { #if (!defined(BUILD_FOR_NT40))
HRESULT hr = S_OK; auto_rel<IAccessor> pAccessor; auto_rel<IColumnsInfo> pColumnsInfo; HACCESSOR hAccessor = NULL; DBBINDING Bindings[1]; CComVariant varData;
if ((NULL == hRow) || (NULL == ppwszURL) || (NULL == pRowset)) RRETURN(E_INVALIDARG);
*ppwszURL = NULL;
// If adspath is in the list of columns selected
// return that value.
if (_fADSPathPresent) { VariantInit(&varData);
Bindings[0].dwPart = DBPART_VALUE; Bindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED; Bindings[0].eParamIO = DBPARAMIO_NOTPARAM; Bindings[0].wType = DBTYPE_VARIANT; Bindings[0].pTypeInfo = NULL; Bindings[0].obValue = 0; Bindings[0].bPrecision = 0; Bindings[0].bScale = 0; Bindings[0].cbMaxLen = sizeof(VARIANT); Bindings[0].pObject = NULL; Bindings[0].pBindExt = NULL; Bindings[0].dwFlags = 0;
hr = pRowset->QueryInterface(IID_IAccessor, (void**)&pAccessor); BAIL_ON_FAILURE(hr);
if (_iAdsPathIndex == 0) { hr = pRowset->QueryInterface(__uuidof(IColumnsInfo), (void **)&pColumnsInfo); BAIL_ON_FAILURE(hr);
hr = GetIndex(pColumnsInfo, L"AdsPath", _iAdsPathIndex); if (0 == _iAdsPathIndex) hr = E_UNEXPECTED;
BAIL_ON_FAILURE(hr); }
Bindings[0].iOrdinal = _iAdsPathIndex; Bindings[0].obValue = NULL;
hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA,sizeof(Bindings)/sizeof(Bindings[0]) , Bindings, 0, &hAccessor, NULL); BAIL_ON_FAILURE(hr); hr = pRowset->GetData(hRow, hAccessor, &varData); BAIL_ON_FAILURE(hr);
ADsAssert(varData.vt == VT_BSTR); ADsAssert(varData.bstrVal);
// allocate the string and copy data
*ppwszURL = (LPWSTR ) _pMalloc->Alloc(sizeof(WCHAR) * (wcslen(varData.bstrVal) + 1)); if (NULL == *ppwszURL) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); }
wcscpy(*ppwszURL, varData.bstrVal);
if (hAccessor) pAccessor->ReleaseAccessor(hAccessor, NULL);
} else { ADS_CASE_IGNORE_STRING padsPath;
hr = ((CRowset *)pRowset)->GetADsPathFromHROW(hRow, &padsPath); BAIL_ON_FAILURE(hr);
*ppwszURL = (LPWSTR ) _pMalloc->Alloc(sizeof(WCHAR) * (wcslen(padsPath) +1)); if (NULL == *ppwszURL) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } wcscpy(*ppwszURL, padsPath);
}
RRETURN(S_OK);
error: if (hAccessor) pAccessor->ReleaseAccessor(hAccessor, NULL); RRETURN(hr); #else
RRETURN(E_FAIL); #endif
}
//+---------------------------------------------------------------------------
//
// Function: CRowProvider::GetColumnInfo
//
// Synopsis: @mfunc Get Column Info.
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowProvider::GetColumnInfo( DBORDINAL * pcColumns, DBCOLUMNINFO ** pprgInfo, WCHAR ** ppStringsBuffer ) { DBORDINAL i; ULONG cChars, cCharDispl; HRESULT hr = S_OK; DBCOLUMNINFO * prgInfo = NULL; WCHAR * pStrBuffer = NULL;
//
// Asserts
//
ADsAssert(_pMalloc); ADsAssert(_cColumns); ADsAssert(_ColInfo); ADsAssert(_pwchBuf);
if( pcColumns ) *pcColumns = 0;
if( pprgInfo ) *pprgInfo = NULL;
if( ppStringsBuffer ) *ppStringsBuffer = NULL;
if( (pcColumns == NULL) || (pprgInfo == NULL) || (ppStringsBuffer == NULL) ) BAIL_ON_FAILURE( hr=E_INVALIDARG );
prgInfo = (DBCOLUMNINFO*)_pMalloc->Alloc((ULONG)(_cColumns * sizeof(DBCOLUMNINFO))); if( prgInfo == NULL ) BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
memcpy(prgInfo, _ColInfo, (size_t)(_cColumns * sizeof(DBCOLUMNINFO)));
cChars = _pMalloc->GetSize(_pwchBuf); pStrBuffer = (WCHAR*)_pMalloc->Alloc(cChars); if( pStrBuffer == NULL ) BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
memcpy(pStrBuffer, (void*)_pwchBuf , cChars);
for (i=1; i<_cColumns; i++) { cCharDispl = (ULONG)(_ColInfo[i].pwszName - _pwchBuf); prgInfo[i].pwszName = pStrBuffer + cCharDispl; prgInfo[i].columnid.uName.pwszName = pStrBuffer + cCharDispl; };
*pcColumns = _cColumns; *pprgInfo = prgInfo; *ppStringsBuffer = pStrBuffer;
RRETURN( S_OK );
error:
if( !prgInfo ) _pMalloc->Free(prgInfo);
if( pStrBuffer != NULL ) _pMalloc->Free(pStrBuffer);
RRETURN( hr ); };
//+---------------------------------------------------------------------------
//
// Function: CRowProvider::MapColumnIDs
//
// Synopsis: @mfunc Map Column IDs.
//
//----------------------------------------------------------------------------
STDMETHODIMP CRowProvider::MapColumnIDs( DBORDINAL cColumnIDs, const DBID rgColumnIDs[], DBORDINAL rgColumns[] ) { ULONG found = 0; DBORDINAL i;
DBORDINAL cValidCols = 0; //
// No Column IDs are set when GetColumnInfo returns ColumnsInfo structure.
// Hence, any value of ID will not match with any column
//
DBORDINAL iCol;
//
// No-Op if cColumnIDs is 0
//
if( cColumnIDs == 0 ) RRETURN( S_OK );
// Spec-defined checks.
// Note that this guarantees we can access rgColumnIDs[] in loop below.
// (Because we'll just fall through.)
if( cColumnIDs && (!rgColumnIDs || !rgColumns) ) RRETURN( E_INVALIDARG );
//
// Set the columns ordinals to invalid values
//
for (iCol=0; iCol < cColumnIDs; iCol++) { // Initialize
rgColumns[iCol] = DB_INVALIDCOLUMN;
//
// The columnid with the Bookmark or the same name
//
if( rgColumnIDs[iCol].eKind == DBKIND_GUID_PROPID && rgColumnIDs[iCol].uGuid.guid == DBCOL_SPECIALCOL && rgColumnIDs[iCol].uName.ulPropid == 2 ) { rgColumns[iCol] = 0; cValidCols++; continue; }
//
// The columnid with the Column Name
//
if( rgColumnIDs[iCol].eKind == DBKIND_NAME && rgColumnIDs[iCol].uName.pwszName ) { //
// Find the name in the list of Attributes
//
for (ULONG iOrdinal=0; iOrdinal < _cColumns; iOrdinal++) { if( _ColInfo[iOrdinal].columnid.eKind == DBKIND_NAME && !_wcsicmp(_ColInfo[iOrdinal].columnid.uName.pwszName, rgColumnIDs[iCol].uName.pwszName) ) { rgColumns[iCol] = iOrdinal; cValidCols++; break; } } } }
if( cValidCols == 0 ) RRETURN( DB_E_ERRORSOCCURRED ); else if( cValidCols < cColumnIDs ) RRETURN( DB_S_ERRORSOCCURRED ); else RRETURN( S_OK ); }
STDMETHODIMP CRowProvider::CopyADs2VariantArray( PADS_SEARCH_COLUMN pADsColumn, PVARIANT *ppVariant ) { SAFEARRAY *aList = NULL; SAFEARRAYBOUND aBound; VARTYPE vType = VT_NULL; HRESULT hr = S_OK; ULONG i; PVARIANT pVariant = NULL, pVarArray = NULL; BOOL fSafeArrayLocked = FALSE;
ADsAssert(ppVariant); *ppVariant = NULL;
aBound.lLbound = 0; aBound.cElements = pADsColumn->dwNumValues;
pVariant = (PVARIANT) AllocADsMem(sizeof(VARIANT)); if (!pVariant) { RRETURN(E_OUTOFMEMORY); }
if ((ULONG) pADsColumn->dwADsType >= g_cMapADsTypeToVarType || (vType = g_MapADsTypeToVarType[pADsColumn->dwADsType]) == VT_NULL) {
BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE); }
aList = SafeArrayCreate( VT_VARIANT, 1, &aBound ); if (aList == NULL) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
hr = SafeArrayAccessData( aList, (void **) &pVarArray ); if (FAILED(hr)) { SafeArrayDestroy( aList ); goto error; }
fSafeArrayLocked = TRUE;
for (i=0; i<aBound.cElements; i++) {
(V_VT(pVarArray+i)) = vType;
switch (vType) { case VT_I4: V_I4(pVarArray+i) = pADsColumn->pADsValues[i].Integer; break;
case VT_DISPATCH: if(pADsColumn->dwADsType == ADSTYPE_LARGE_INTEGER) hr = PackLargeInteger(&pADsColumn->pADsValues[i].LargeInteger, pVarArray+i); else if(pADsColumn->dwADsType == ADSTYPE_DN_WITH_BINARY) hr = PackDNWithBinary(pADsColumn->pADsValues[i].pDNWithBinary, pVarArray+i); else if(pADsColumn->dwADsType == ADSTYPE_DN_WITH_STRING) hr = PackDNWithString(pADsColumn->pADsValues[i].pDNWithString, pVarArray+i);
BAIL_ON_FAILURE(hr); break;
case VT_BOOL: V_I4(pVarArray+i) = pADsColumn->pADsValues[i].Boolean ? VARIANT_TRUE: VARIANT_FALSE; break;
case VT_BSTR: hr = ADsAllocString ( pADsColumn->pADsValues[i].CaseIgnoreString, &(V_BSTR(pVarArray+i)) ); BAIL_ON_FAILURE(hr); break;
case VT_DATE: { double date = 0; hr = SystemTimeToVariantTime( &pADsColumn->pADsValues[i].UTCTime, &date); BAIL_ON_FAILURE(hr); V_DATE(pVarArray+i)= date; break; }
case (VT_UI1 | VT_ARRAY): VariantInit(pVarArray+i);
if(pADsColumn->dwADsType == ADSTYPE_OCTET_STRING) hr = BinaryToVariant( pADsColumn->pADsValues[i].OctetString.dwLength, pADsColumn->pADsValues[i].OctetString.lpValue, pVarArray+i); else if(pADsColumn->dwADsType == ADSTYPE_NT_SECURITY_DESCRIPTOR) hr = BinaryToVariant( pADsColumn->pADsValues[i].SecurityDescriptor.dwLength, pADsColumn->pADsValues[i].SecurityDescriptor.lpValue, pVarArray+i); else if(pADsColumn->dwADsType == ADSTYPE_PROV_SPECIFIC) hr = BinaryToVariant( pADsColumn->pADsValues[i].ProviderSpecific.dwLength, pADsColumn->pADsValues[i].ProviderSpecific.lpValue, pVarArray+i);
BAIL_ON_FAILURE(hr); break;
default: BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE); break; }
}
fSafeArrayLocked = FALSE; SafeArrayUnaccessData( aList );
V_VT((PVARIANT)pVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY((PVARIANT)pVariant) = aList;
*ppVariant = pVariant;
RRETURN(S_OK);
error:
if (fSafeArrayLocked && (NULL != aList)) { SafeArrayUnaccessData( aList ); SafeArrayDestroy( aList ); }
if (pVariant) { FreeADsMem(pVariant); } RRETURN(hr);
}
HRESULT PackLargeInteger( LARGE_INTEGER *plargeint, PVARIANT pVarDestObject ) { HRESULT hr = S_OK; IADsLargeInteger * pLargeInteger = NULL; IDispatch * pDispatch = NULL;
hr = CoCreateInstance( CLSID_LargeInteger, NULL, CLSCTX_INPROC_SERVER, IID_IADsLargeInteger, (void **) &pLargeInteger); BAIL_ON_FAILURE(hr);
hr = pLargeInteger->put_LowPart(plargeint->LowPart); BAIL_ON_FAILURE(hr);
hr = pLargeInteger->put_HighPart(plargeint->HighPart); BAIL_ON_FAILURE(hr);
hr = pLargeInteger->QueryInterface( IID_IDispatch, (void **) &pDispatch ); BAIL_ON_FAILURE(hr);
V_VT(pVarDestObject) = VT_DISPATCH; V_DISPATCH(pVarDestObject) = pDispatch;
error:
if (pLargeInteger) { pLargeInteger->Release(); } RRETURN(hr); }
HRESULT PackDNWithBinary( PADS_DN_WITH_BINARY pDNWithBinary, PVARIANT pVarDestObject ) { HRESULT hr; IADsDNWithBinary *pIADsDNWithBinary = NULL; BSTR bstrTemp = NULL; SAFEARRAYBOUND aBound; SAFEARRAY *aList = NULL; CHAR HUGEP *pArray = NULL; IDispatch *pIDispatch = NULL;
if( (NULL == pDNWithBinary) || (NULL == pVarDestObject) ) BAIL_ON_FAILURE(hr = E_INVALIDARG);
hr = CoCreateInstance( CLSID_DNWithBinary, NULL, CLSCTX_INPROC_SERVER, IID_IADsDNWithBinary, (void **) &pIADsDNWithBinary ); BAIL_ON_FAILURE(hr);
if (pDNWithBinary->pszDNString) { hr = ADsAllocString(pDNWithBinary->pszDNString, &bstrTemp); BAIL_ON_FAILURE(hr);
//
// Put the value in the object - we can only set BSTR's
//
hr = pIADsDNWithBinary->put_DNString(bstrTemp); BAIL_ON_FAILURE(hr); }
aBound.lLbound = 0; aBound.cElements = pDNWithBinary->dwLength;
aList = SafeArrayCreate( VT_UI1, 1, &aBound );
if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); }
hr = SafeArrayAccessData( aList, (void HUGEP * FAR *) &pArray ); BAIL_ON_FAILURE(hr);
memcpy( pArray, pDNWithBinary->lpBinaryValue, aBound.cElements );
SafeArrayUnaccessData( aList );
V_VT(pVarDestObject) = VT_ARRAY | VT_UI1; V_ARRAY(pVarDestObject) = aList;
hr = pIADsDNWithBinary->put_BinaryValue(*pVarDestObject); VariantClear(pVarDestObject); BAIL_ON_FAILURE(hr);
hr = pIADsDNWithBinary->QueryInterface( IID_IDispatch, (void **) &pIDispatch ); BAIL_ON_FAILURE(hr);
V_VT(pVarDestObject) = VT_DISPATCH; V_DISPATCH(pVarDestObject) = pIDispatch;
error: if(pIADsDNWithBinary) pIADsDNWithBinary->Release();
if (bstrTemp) ADsFreeString(bstrTemp);
RRETURN(hr); }
HRESULT PackDNWithString( PADS_DN_WITH_STRING pDNWithString, PVARIANT pVarDestObject ) { HRESULT hr; IADsDNWithString *pIADsDNWithString = NULL; BSTR bstrDNVal = NULL; BSTR bstrStrVal = NULL; IDispatch *pIDispatch;
if( (NULL == pDNWithString) || (NULL == pVarDestObject) ) BAIL_ON_FAILURE(hr = E_INVALIDARG);
hr = CoCreateInstance( CLSID_DNWithString, NULL, CLSCTX_INPROC_SERVER, IID_IADsDNWithString, (void **) &pIADsDNWithString ); BAIL_ON_FAILURE(hr);
if (pDNWithString->pszDNString) { hr = ADsAllocString(pDNWithString->pszDNString, &bstrDNVal); BAIL_ON_FAILURE(hr);
hr = pIADsDNWithString->put_DNString(bstrDNVal); BAIL_ON_FAILURE(hr); }
if (pDNWithString->pszStringValue) { hr = ADsAllocString( pDNWithString->pszStringValue, &bstrStrVal ); BAIL_ON_FAILURE(hr);
hr = pIADsDNWithString->put_StringValue(bstrStrVal);
BAIL_ON_FAILURE(hr); }
hr = pIADsDNWithString->QueryInterface( IID_IDispatch, (void **) &pIDispatch ); BAIL_ON_FAILURE(hr);
V_VT(pVarDestObject) = VT_DISPATCH; V_DISPATCH(pVarDestObject) = pIDispatch;
error:
if(pIADsDNWithString) pIADsDNWithString->Release();
if (bstrDNVal) { ADsFreeString(bstrDNVal); }
if (bstrStrVal) { ADsFreeString(bstrStrVal); }
RRETURN(hr); }
HRESULT CRowProvider::SeekToNextRow(void) { HRESULT hr; DWORD dwExtError = ERROR_SUCCESS; const int ERROR_BUF_SIZE = 512; const int NAME_BUF_SIZE = 128; WCHAR ErrorBuf[ERROR_BUF_SIZE]; WCHAR NameBuf[NAME_BUF_SIZE];
do { // Clear the ADSI extended error, so that after the call to GetNextRow,
// we can safely check if an extended error was set.
ADsSetLastError(ERROR_SUCCESS, NULL, NULL); dwExtError = ERROR_SUCCESS;
//
// read the next row
//
hr = _pDSSearch->GetNextRow( _hSearchHandle );
// we should treat SIZE_LIMIT_EXCEEDED error message as
// S_ADS_NOMORE_ROWS
// in the future, we might want to return this error message
// to the user under non-paged search situation
if (LIMIT_EXCEEDED_ERROR(hr)) hr = S_ADS_NOMORE_ROWS; BAIL_ON_FAILURE( hr );
if (hr == S_ADS_NOMORE_ROWS) { // check if more results are likely (pagedTimeLimit search). If so,
// we will keep trying till a row is obtained.
hr = ADsGetLastError(&dwExtError, ErrorBuf, ERROR_BUF_SIZE, NameBuf, NAME_BUF_SIZE); BAIL_ON_FAILURE(hr);
if (dwExtError != ERROR_MORE_DATA) // we really have no more data
RRETURN(S_ADS_NOMORE_ROWS); } } while(ERROR_MORE_DATA == dwExtError);
error: RRETURN(hr); }
HRESULT CRowProvider::SeekToPreviousRow(void) { RRETURN( _pDSSearch->GetPreviousRow(_hSearchHandle) ); }
|