windows-nt/Source/XPSP1/NT/ds/adsi/ldap/cumicurs.cxx
2020-09-26 16:20:57 +08:00

813 lines
20 KiB
C++

//----------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: cumicurs.cxx
//
// Contents: Contains the UMI cursor object implementation. There are 2
// ways to use this object. One is to initialize with an
// IADsContainer pointer and the other is to use an IUmiQuery obj.
//
// History: 03-16-00 SivaramR Created (in WinNT)
// 03-28-00 AjayR modified for LDAP.
//
//----------------------------------------------------------------------------
#include "ldap.hxx"
//+---------------------------------------------------------------------------
// Function: CUmiCursor::CUmiCursor
//
// Synopsis: Constructor
//
// Arguments: None
//
// Returns: N/A
//
// Modifies: N/A
//
//----------------------------------------------------------------------------
CUmiCursor::CUmiCursor():
_pPropMgr(NULL),
_ulErrorStatus(0),
_pIID(NULL),
_pContainer(NULL),
_pEnum(NULL),
_pSearchHelper(NULL),
_fQuery(FALSE)
{
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::~CUmiCursor
//
// Synopsis: Destructor
//
// Arguments: None
//
// Returns: N/A
//
// Modifies: N/A
//
//----------------------------------------------------------------------------
CUmiCursor::~CUmiCursor()
{
if (_pPropMgr) {
delete _pPropMgr;
}
if (_pContainer) {
_pContainer->Release();
}
if (_pIID){
FreeADsMem(_pIID);
}
if (_pEnum) {
_pEnum->Release();
}
if (_pSearchHelper) {
delete _pSearchHelper;
}
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::CreateCursor (static constructor overloaded)
//
// Synopsis: Creats a UmiCursor object in the container mode.
//
// Arguments: *pCont - Pointer to container we are enumerating.
// iid - IID requested on returned object.
// ppInterface - Ptr to return value.
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: ppInterface to point to new cursor object.
//
//----------------------------------------------------------------------------
HRESULT
CUmiCursor::CreateCursor(
IUnknown *pCont,
REFIID iid,
LPVOID *ppInterface
)
{
CUmiCursor *pCursor = NULL;
CPropertyManager *pPropMgr = NULL;
IADsContainer *pContainer = NULL;
HRESULT hr = S_OK;
ADsAssert(ppInterface);
ADsAssert(pCont);
pCursor = new CUmiCursor();
if (!pCursor) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Initialize the various params on this object.
//
hr = CPropertyManager::CreatePropertyManager(
(IUnknown *) pCursor,
NULL, // IADs ptr
NULL, // pCreds
IntfPropsCursor,
&pPropMgr
);
BAIL_ON_FAILURE(hr);
hr = pCont->QueryInterface(
IID_IADsContainer,
(void **) &pContainer
);
BAIL_ON_FAILURE(hr);
hr = pCursor->QueryInterface(iid, ppInterface);
BAIL_ON_FAILURE(hr);
//
// Ref on this object is now 2, release the additional ref.
//
pCursor->Release();
pCursor->_pContainer = pContainer;
pCursor->_pPropMgr = pPropMgr;
pCursor->_pIID = NULL;
pCursor->_ulErrorStatus = 0;
RRETURN(S_OK);
error:
if (pCursor) {
delete pCursor;
}
if (pPropMgr) {
delete pPropMgr;
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::CreateCursor (static constructor overloaded).
//
// Synopsis: Creats a UmiCursor object in the query mode. Most of the
// params are needed for creating the search helper object.
//
// Arguments: pQuery - Query being executed.
// pConnection - Connection being used for query.
// pUnk - ???.
// pszADsPath - Path of object query is being executed on.
// pszLdapServer - Server of object being queried.
// pszLdapDn - Dn of the object being searched.
// cCredentials - Credentials to use for query.
// dwPort - Port being used for connection.
// iid - Cursor iid requested
//
// Returns: HRESULT - S_OK or any failure error code.
//
// Modifies: ppInterface to point to new cursor object.
//
//----------------------------------------------------------------------------
HRESULT
CUmiCursor::CreateCursor(
IUmiQuery *pQuery,
IUmiConnection *pConnection,
IUnknown *pUnk,
LPCWSTR pszADsPath,
LPCWSTR pszLdapServer,
LPCWSTR pszLdapDn,
CCredentials cCredentials,
DWORD dwPort,
REFIID iid,
LPVOID *ppInterface
)
{
CUmiCursor *pCursor = NULL;
CPropertyManager *pPropMgr = NULL;
HRESULT hr = S_OK;
CUmiSearchHelper *pSearchHelper = NULL;
ADsAssert(ppInterface);
hr = CUmiSearchHelper::CreateSearchHelper(
pQuery,
pConnection,
pUnk,
pszADsPath,
pszLdapServer,
pszLdapDn,
cCredentials,
dwPort,
&pSearchHelper
);
BAIL_ON_FAILURE(hr);
pCursor = new CUmiCursor();
if (!pCursor) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Initialize the various params on this object.
//
hr = CPropertyManager::CreatePropertyManager(
(IUnknown *) pCursor,
NULL, // pIADs
NULL, // pCreds
IntfPropsCursor,
&pPropMgr
);
BAIL_ON_FAILURE(hr);
hr = pCursor->QueryInterface(iid, ppInterface);
BAIL_ON_FAILURE(hr);
//
// Ref on this object is now 2, release the additional ref.
//
pCursor->Release();
pCursor->_pSearchHelper = pSearchHelper;
pCursor->_pPropMgr = pPropMgr;
pCursor->_pIID = NULL;
pCursor->_ulErrorStatus = 0;
pCursor->_fQuery = TRUE;
RRETURN(S_OK);
error:
if (pCursor) {
delete pCursor;
}
if (pSearchHelper) {
delete pSearchHelper;
}
if (pPropMgr) {
delete pPropMgr;
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::QueryInterface (IUnknown interface).
//
// Synopsis: Standard QueryInterface function.
//
// Arguments: Self explanatory.
//
// Returns: S_OK on success or any suitable error code.
//
// Modifies: *ppInterface to return interface pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUmiCursor::QueryInterface(
REFIID iid,
LPVOID *ppInterface
)
{
if (!ppInterface)
RRETURN(E_INVALIDARG);
if (IsEqualIID(iid, IID_IUnknown)) {
*ppInterface = (IUmiCursor *) this;
}
else if (IsEqualIID(iid, IID_IUmiBaseObject)) {
*ppInterface = (IUmiCursor *) this;
}
else if (IsEqualIID(iid, IID_IUmiPropList)) {
*ppInterface = (IUmiCursor *) this;
}
else if (IsEqualIID(iid, IID_IUmiCursor)) {
*ppInterface = (IUmiCursor *) this;
}
else {
*ppInterface = NULL;
RRETURN(E_NOINTERFACE);
}
AddRef();
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::GetLastStatus (IUmiBaseObject method).
//
// Synopsis: Returns only numeric status code from the last operation.
//
// Arguments: uFlags - Only 0 is supported for now.
// puSpecificStatus - Returns status/error code.
// riid - Not used.
// pStatusObj - NULL, not used currently.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *puSpecificStatus to return appropriate status code.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUmiCursor::GetLastStatus(
ULONG uFlags,
ULONG *puSpecificStatus,
REFIID riid,
LPVOID *pStatusObj
)
{
if (uFlags != 0) {
RRETURN(UMI_E_INVALID_FLAGS);
}
if (!puSpecificStatus) {
RRETURN(E_INVALIDARG);
}
if (pStatusObj) {
//
// Should we error out ?
//
*pStatusObj = NULL;
}
*puSpecificStatus = _ulErrorStatus;
RRETURN(UMI_S_NO_ERROR);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::GetInterfacePropList (IUmiBaseObject method).
//
// Synopsis: Returns a pointer to the interface property list for
// cursor object.
//
// Arguments: uFlags - Flags, only 0 is supported.
// ppPropList - Return value.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pPropList changed to IUmiPropList pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUmiCursor::GetInterfacePropList(
ULONG uFlags,
IUmiPropList **ppPropList
)
{
HRESULT hr = UMI_S_NO_ERROR;
SetLastStatus(0);
if (uFlags != 0) {
RRETURN(UMI_E_INVALID_FLAGS);
}
if (!ppPropList) {
RRETURN(E_INVALIDARG);
}
hr = _pPropMgr->QueryInterface(IID_IUmiPropList, (void **)ppPropList);
if (FAILED(hr)) {
SetLastStatus(hr);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::SetLastStatus (internal private helper routine).
//
// Synopsis: Sets the status of the last operation. If the status is one
// of the pre-defined error codes, then the status is just set to
// 0 since we are not adding any value by returning the same
// status as the error code.
//
// Arguments: ulStatus - Status to be set.
//
// Returns: Nothing
//
// Modifies: Internal member status variable.
//
//----------------------------------------------------------------------------
void
CUmiCursor::SetLastStatus(ULONG ulStatus)
{
this->_ulErrorStatus = ulStatus;
return;
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::SetIID (IUmiCursor method).
//
// Synopsis: Sets the interface to be requested off each item returned by
// the enumerator. Default is IID_IUmiObject.
//
// Arguments: riid - IID of interface to request.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUmiCursor::SetIID(
REFIID riid
)
{
SetLastStatus(0);
if (_fQuery) {
RRETURN(this->_pSearchHelper->SetIID(riid));
}
else {
if (!_pIID){
_pIID = (IID *) AllocADsMem(sizeof(IID));
if (!_pIID){
RRETURN(E_OUTOFMEMORY);
}
}
memcpy(_pIID, &riid, sizeof(IID));
}
RRETURN(UMI_S_NO_ERROR);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::Reset (IUmiCursor method).
//
// Synopsis: Resets the enumerator to restart from begining (this is for
// likely to return an error for the IADsContainer case).
//
// Arguments: N/A.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUmiCursor::Reset(void)
{
HRESULT hr = E_NOTIMPL;
RRETURN(hr);
//
// Rest of the code can be invoked when we have proper support.
//
SetLastStatus(0);
if (!_fQuery) {
//
// it is possible that _pEnum may be NULL here if the user
// called Reset before calling Next()
//
if (!_pEnum) {
RRETURN(UMI_S_NO_ERROR);
}
hr = _pEnum->Reset();
BAIL_ON_FAILURE(hr);
hr = S_OK;
}
else {
hr = _pSearchHelper->Reset();
}
error:
if (FAILED(hr)) {
SetLastStatus(hr);
hr = MapHrToUmiError(hr);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::GetFilter (internal private helper routine).
//
// Synopsis: Gets the filter from the interface property cache. If the
// interface property was not set, an emty variant is returned.
//
// Arguments: pvFilter - ptr to variant for return value.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pvFilter to return the filter.
//
//----------------------------------------------------------------------------
HRESULT
CUmiCursor::GetFilter(VARIANT *pvFilter)
{
HRESULT hr = UMI_S_NO_ERROR;
UMI_PROPERTY_VALUES *pUmiProp = NULL;
LPWSTR *ppszFilters = NULL;
DWORD dwNumFilters = 0;
ADsAssert(pvFilter);
VariantInit(pvFilter);
hr = _pPropMgr->Get(
L"__FILTER",
0,
&pUmiProp
);
if (hr == UMI_E_NOT_FOUND) {
//
// interface property was not set. Return empty variant.
//
RRETURN(hr);
}
BAIL_ON_FAILURE(hr);
ADsAssert(pUmiProp->pPropArray->uType == UMI_TYPE_LPWSTR);
//
// Make sure we have data back and that it is not just NULL.
// We will not get back a NULL string but instead an array with
// one element that is NULL. That is as good as no filter.
//
if (pUmiProp->pPropArray->uCount
&& pUmiProp->pPropArray->pUmiValue
&& pUmiProp->pPropArray->pUmiValue->pszStrValue[0]
) {
//
// Valid filter is present.
//
ppszFilters = pUmiProp->pPropArray->pUmiValue->pszStrValue;
dwNumFilters = pUmiProp->pPropArray->uCount;
hr = ADsBuildVarArrayStr(ppszFilters, dwNumFilters, pvFilter);
BAIL_ON_FAILURE(hr);
}
else {
hr = UMI_E_NOT_FOUND;
}
error:
if (pUmiProp) {
_pPropMgr->FreeMemory(0, pUmiProp);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: CUmiCursor::Next (IUmiCursor method).
//
// Synopsis: Returns the next "n" item(s) in the enumeration sequence.
//
// Arguments: uNumRequested - Number of items requested.
// pNumReturned - Returns actual number of objects returned.
// ppObjects - Array of interface pointers of size
// *pNumReturned.
//
// Returns: UMI_S_NO_ERROR on success. Error code otherwise.
//
// Modifies: *pNumReturned to return the number of objects returned
// *ppObjects to return the interface pointers
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUmiCursor::Next(
ULONG uNumRequested,
ULONG *puNumReturned,
LPVOID *ppObjects
)
{
HRESULT hr = S_OK;;
VARIANT vFilter, *pvResults = NULL;
ULONG ulIndex = 0, uNumReturned = 0, uNumResults = 0;
IDispatch *pDisp = NULL;
IUnknown **pUnkArr = NULL, *pTmpUnk = NULL;
VARIANT vOldFilter;
BOOL fReplaceFilter = FALSE;
SetLastStatus(0);
VariantInit(&vOldFilter);
if ( (!puNumReturned) || (!ppObjects) ){
RRETURN(E_INVALIDARG);
}
*puNumReturned = 0;
*ppObjects = NULL;
//
// If this is a query then we need to get the results from the
// query object.
//
if (_fQuery) {
hr = _pSearchHelper->Next(
uNumRequested,
puNumReturned,
ppObjects
);
//
// MapHrToUmiError
//
RRETURN(hr);
}
//
// If we get here this is a container enumerate.
//
VariantInit(&vFilter);
if (!_pEnum) {
//
// first call to Next()
//
ADsAssert(_pContainer);
//
// check if the user set a filter on the cursor
//
hr = GetFilter(&vFilter);
if (SUCCEEDED(hr)) {
//
// We need to get the old filter to restore it.
//
hr = _pContainer->get_Filter(&vOldFilter);
if (SUCCEEDED(hr)) {
fReplaceFilter = TRUE;
}
//
// We have a valid filter that we need to set.
//
hr = _pContainer->put_Filter(vFilter);
}
else if (hr == UMI_E_NOT_FOUND) {
//
// Reset error as this one is expected, anything else we bail.
//
hr = S_OK;
}
//
// Catch either GetFilter failure or put_Filter failure.
//
BAIL_ON_FAILURE(hr);
hr = _pContainer->get__NewEnum((IUnknown **) &_pEnum);
//
// Restore old filter irrespective of ECODE.
//
if (fReplaceFilter) {
_pContainer->put_Filter(vOldFilter);
}
BAIL_ON_FAILURE(hr);
}
//
// allocate memory for variants to return objects
//
pvResults = (VARIANT *) AllocADsMem(uNumRequested * sizeof(VARIANT));
if (!pvResults) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
hr = _pEnum->Next(
uNumRequested,
pvResults,
&uNumReturned
);
BAIL_ON_FAILURE(hr);
if (!uNumReturned) {
//
// This will handle the S_FALSE case.
//
goto error;
}
//
// allocate memory for array of interface pointers to return
//
pUnkArr = (IUnknown **) AllocADsMem(uNumReturned * sizeof(IUnknown *));
if (!pUnkArr) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// convert the V_DISPATCH variants to the requested interface properties
//
for(ulIndex = 0; ulIndex < uNumReturned; ulIndex++) {
pDisp = V_DISPATCH(&pvResults[ulIndex]);
if (_pIID) {
hr = pDisp->QueryInterface(*_pIID, (void **) &pTmpUnk);
}
else {
hr = pDisp->QueryInterface(IID_IUmiObject, (void **) &pTmpUnk);
}
//
// Is this really correct ?
//
if (FAILED(hr)) {
continue;
}
pUnkArr[uNumResults] = pTmpUnk;
uNumResults++;
}
*puNumReturned = uNumResults;
if (uNumResults > 0) {
*ppObjects = pUnkArr;
}
else {
FreeADsMem(pUnkArr);
}
error:
VariantClear(&vFilter);
VariantClear(&vOldFilter);
if (pvResults) {
for(ulIndex = 0; ulIndex < uNumReturned; ulIndex++) {
VariantClear(&pvResults[ulIndex]);
}
FreeADsMem(pvResults);
}
if (FAILED(hr)) {
SetLastStatus(hr);
hr = MapHrToUmiError(hr);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: Count
//
// Synopsis: Counts the number of results returned by the enumerator.
// Not implemented currently.
//
// Arguments:
//
// None
//
// Returns: E_NOTIMPL for now.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::Count(
ULONG *puNumObjects
)
{
SetLastStatus(0);
RRETURN(E_NOTIMPL);
}
//+---------------------------------------------------------------------------
// Function: Previous
//
// Synopsis: Returnss the previous object returned by the enumerator.
// Not implemented currently.
//
// Arguments:
//
// None
//
// Returns: E_NOTIMPL for now.
//
// Modifies: Nothing.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUmiCursor::Previous(
ULONG uFlags,
LPVOID *pObj
)
{
SetLastStatus(0);
RRETURN(E_NOTIMPL);
}