WindowsXP-SP1/ds/adsi/router/crowprov.cxx

1351 lines
39 KiB
C++

//-----------------------------------------------------------------------------
//
// 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;
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;
}
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))
);
if (FAILED(hr)) {
SafeArrayUnaccessData( aList );
SafeArrayDestroy( aList );
goto error;
}
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:
SafeArrayUnaccessData( aList );
SafeArrayDestroy( aList );
BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
break;
}
}
SafeArrayUnaccessData( aList );
V_VT((PVARIANT)pVariant) = VT_ARRAY | VT_VARIANT;
V_ARRAY((PVARIANT)pVariant) = aList;
*ppVariant = pVariant;
RRETURN(S_OK);
error:
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) );
}