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