Directory Services |
The following C++ code example contains a function that uses ranging to retrieve the members of a group using the IDirectorySearch interface.
HRESULT EnumGroupWithIDirectorySearch(LPCWSTR pwszGroupDN, LPCWSTR pwszUsername, LPCWSTR pwszPassword) { if(NULL == pwszGroupDN) { return E_POINTER; } HRESULT hr; IDirectorySearch *pSearch; hr = ADsOpenObject( pwszGroupDN, pwszUsername, pwszPassword, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (void**)&pSearch); if(SUCCEEDED(hr)) { const DWORD dwStep = 1000; DWORD dwLowRange; DWORD dwHighRange; BOOL fLastQuery; BOOL fExit; // Only search for properties of this object. ADS_SEARCHPREF_INFO rgSearchPrefs[1]; rgSearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; rgSearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER; rgSearchPrefs[0].vValue.Integer = ADS_SCOPE_BASE; // Set the search preference. hr = pSearch->SetSearchPreference(rgSearchPrefs, 1); if (FAILED(hr)) { return hr; } dwLowRange = 0; dwHighRange = dwLowRange + (dwStep - 1); // Set the search filter. LPWSTR pszSearch = L"(CN=*)"; fLastQuery = FALSE; fExit = FALSE; do { WCHAR wszName[] = L"name"; WCHAR wszAttribute[MAX_PATH]; ADS_SEARCH_HANDLE hSearch; if(fLastQuery) { // Perform this query with the "range=<lowRange>-*" range. wsprintfW(wszAttribute, L"member;range=%d-*", dwLowRange); } else { // Perform this query with the "range=<lowRange>-<highRange>" range. wsprintfW(wszAttribute, L"member;range=%d-%d", dwLowRange, dwHighRange); } OutputDebugStringW(L"Query:"); OutputDebugStringW(wszAttribute); OutputDebugStringW(L"\n"); LPWSTR rgAttributes[2] = {wszName, wszAttribute}; // Execute the query. hr = pSearch->ExecuteSearch(pszSearch, rgAttributes, 2, &hSearch); if(SUCCEEDED(hr)) { // Enumerate the rows. while(SUCCEEDED(hr = pSearch->GetNextRow(hSearch))) { if(S_OK == hr) { LPWSTR pwszColumnName; hr = pSearch->GetNextColumnName(hSearch, &pwszColumnName); if(SUCCEEDED(hr)) { /* If the column name retrieved from the server is different than the query string, this indicates that last range requested was beyond the range of property values. Perform one last query with the "range=<lowRange>-*" range. */ if(0 != lstrcmpiW(pwszColumnName, wszAttribute)) { if(fLastQuery) { /* The request failed to retrieve the attribute in two of two attempts. This will occur if the group has no members. Exit the loop to avoid an infinite loop condition. */ fExit = TRUE; } fLastQuery = TRUE; FreeADsMem(pwszColumnName); break; } else { ADS_SEARCH_COLUMN col; // Get the column. hr = pSearch->GetColumn(hSearch, pwszColumnName, &col); if(SUCCEEDED(hr)) { DWORD i; // Enumerate the retrieved property values. for(i = 0; i < col.dwNumValues; i++) { wprintf(L"%s\n", col.pADsValues[i].CaseIgnoreString); } // Free the column. pSearch->FreeColumn(&col); } FreeADsMem(pwszColumnName); if(fLastQuery) { /* The last query was just completed, so exit the loop. */ fExit = TRUE; break; } } } } else if(S_ADS_NOMORE_ROWS == hr) { /* Call ADsGetLastError to verify that the search is waiting for a response to a previous query. */ DWORD dwError = ERROR_SUCCESS; WCHAR szError[512]; WCHAR szProvider[512]; ADsGetLastError(&dwError, szError, 512, szProvider, 512); if(ERROR_MORE_DATA != dwError) { break; } /* The search is waiting for a response to a previous query. Call GetNextRow again. */ } else { break; } } // Close the search handle to cleanup. pSearch->CloseSearchHandle(hSearch); // If the last query was just performed, exit the loop. if(!fLastQuery) { // Increment the high and low ranges to query for the next block of objects. dwLowRange = dwHighRange + 1; dwHighRange = dwLowRange + (dwStep - 1); } } }while(!fExit); pSearch->Release(); } return hr; }