STDMETHODIMP CLDAPQuery::nextResults( /* [in] */ LONG results_id, /* [in] */ ULONG num_results, /* [retval][out] */ SAFEARRAY** result) { CComSafeArray<VARIANT> dnList(0UL); ÑConnectInfo *cinfo = NULL; ÑResultsInfo *presinfo = NULL; m_errorCode = 0L; for(int i = 0; i < m_connections.GetSize(); i++) { ÑConnectInfo * const currentConnectInfo = m_connections.GetValueAt(i); if(currentConnectInfo) { ÑResultsInfo * const resInfo = currentConnectInfo->findResult(results_id); if(resInfo) { cinfo = currentConnectInfo; presinfo = resInfo; break; } } } if(cinfo && presinfo && presinfo->pages()) { const PLDAP ld = cinfo->ld(); const PLDAPSearch pPages = presinfo->pages(); PLDAPMessage pMsg = NULL; const BOOL allResults = (num_results == 0UL); while((allResults || num_results > 0UL) && (m_errorCode = ldap_get_next_page_s(ld, pPages, NULL, (num_results < 1000UL && num_results > 0UL ? num_results : 1000UL), NULL, &pMsg)) == LDAP_SUCCESS) //not more the 1k results per query { if(pMsg) { for(PLDAPMessage entry = ldap_first_entry(ld, pMsg); entry != NULL && (allResults || num_results-- > 0UL); entry = ldap_next_entry(ld, entry)) { CComObject<CAssocObject> *obj; CComObject<CAssocObject>::CreateInstance(&obj); const PTCHAR dn = ldap_get_dn(ld, entry); obj->AddValue(_T("dn"), CComVariant(dn)); PTCHAR attr; BerElement* berElem = NULL; for(attr = ldap_first_attribute(ld, entry, &berElem); attr != NULL; attr = ldap_next_attribute(ld, entry, berElem)) { bool single = false; const AttrSchema* const schema = cinfo->attrSchemaLookup(attr); if(schema) { single = schema->single; if(schema->type == OctetString) //we need to work different only with binary data { PBERVAL *vals; if((vals = ldap_get_values_len(ld, entry, attr)) != NULL) { if(!single) { CComSafeArray<VARIANT> attrValues(ldap_count_values_len(vals)); for(LONG i = 0L; vals[i] != NULL; i++) { attrValues[i] = CAttributesSchema::getAttributeVariant(vals[i], schema->type); } obj->AddValue(attr, CComVariant(attrValues)); } else { obj->AddValue(attr, CAttributesSchema::getAttributeVariant(vals[0], schema->type)); } ldap_value_free_len(vals); } ldap_memfree(attr); continue; } } PTCHAR *vals; if((vals = ldap_get_values(ld, entry, attr)) != NULL && ldap_count_values(vals) > 0UL) { if(!single) { CComSafeArray<VARIANT> attrValues(ldap_count_values(vals)); for(LONG i = 0L; vals[i] != NULL; i++) { attrValues[i] = CComVariant(vals[i]); } obj->AddValue(attr, CComVariant(attrValues)); } else { obj->AddValue(attr, CComVariant(vals[0])); } ldap_value_free(vals); } else { BOOL last = FALSE; LONG start = 0L; CComSafeArray<VARIANT> attrValues(0UL); do { CString attrWithRange; if(last) attrWithRange.Format(_T("%s;range=%ld-*"), attr, start); else attrWithRange.Format(_T("%s;range=%ld-%ld"), attr, start, start+999L); CSimpleArray<PTCHAR> a; a.Add(attrWithRange.GetBuffer()); a.Add(NULL); PLDAPMessage pItemMsg = NULL; if(ldap_search_s(ld, dn, LDAP_SCOPE_BASE, _T("(objectClass=*)"), a.GetData(), 0, &pItemMsg) == LDAP_SUCCESS) { PLDAPMessage const itemEntry = ldap_first_entry(ld, pItemMsg); if(itemEntry) { if((vals = ldap_get_values(ld, itemEntry, attrWithRange.GetBuffer())) != NULL) { if(ldap_count_values(vals) == 0) { if(last) start = -1L; //leave loop if already last last = TRUE; } else { for(LONG i = 0L; vals[i] != NULL; i++) { attrValues.Add(CComVariant(vals[i])); } if(last) start = -1L; //leave loop else start += 1000L; //next results } ldap_value_free(vals); } else { if(last) start = -1L; //leave loop if already last last = TRUE; } } else { start = -1L; //leave loop } ldap_msgfree(pItemMsg); } else { start = -1L; //leave loop } } while (start >= 0L); obj->AddValue(attr, CComVariant(attrValues)); } ldap_memfree(attr); } dnList.Add(CComVariant(obj)); ldap_memfree(dn); } ldap_msgfree(pMsg); } } if(m_errorCode != LDAP_SUCCESS && m_errorCode != LDAP_SIZELIMIT_EXCEEDED) { cinfo->removeResult(results_id); } if(m_errorCode == LDAP_NO_RESULTS_RETURNED || m_errorCode == LDAP_MORE_RESULTS_TO_RETURN || m_errorCode == LDAP_SIZELIMIT_EXCEEDED) m_errorCode = LDAP_SUCCESS; } *result = dnList.Detach(); return S_OK; }