Platform SDK: Active Directory, ADSI, and Directory Services |
The following code fragment contains a function that uses ranging to retrieve the members of a group using IDirectoryObject:
//////////////////////////////////////////////////////////////////////////////////////////////////// /* PrintAttributeWithRanging() - Uses IDirectoryObject to read an attribute with ADSI ranging Parameters IDirectoryObject * pDirObject - Object from which the attribute will be read LPOLESTR pwszAttribute - Name of the attribute int iNumToDisplayAtATime - Number of Attributes to retrieve at a time */ HRESULT PrintAttributeWithRanging(IDirectoryObject * pDirObject,LPOLESTR pwszAttribute, int iNumToDisplayAtATime) { HRESULT hr = S_OK; ADS_ATTR_INFO *pAttrInfo=NULL; // Returned Data DWORD dwReturn; // number of returned elements WCHAR pwszRangeAttrib[512]; // String for building Range LPWSTR pAttrNames[]={pwszRangeAttrib}; // Array for passing attribute array DWORD dwNumAttr =sizeof(pAttrNames)/sizeof(LPWSTR); // Number of attributes requested // Do a series of range searches, grabbing // iNumToDisplayAtATime at a time. int iRange = 0; DWORD dAttribsGotten = 0; while (SUCCEEDED(hr)) { int iAttribsGottenLastSrch =0; // Build the Range String : ex: L"Member;Range=0-5" swprintf(pwszRangeAttrib,L"%s;Range=%d-%d",pwszAttribute,iRange,iRange+iNumToDisplayAtATime-1); // Get the object Attributes hr = pDirObject->GetObjectAttributes(pAttrNames, dwNumAttr, &pAttrInfo, &dwReturn ); if(SUCCEEDED(hr)) { // Loop through all the rows returned for (DWORD x = 0; x< dwReturn; x++) { // Switch on TYPE returned switch ((pAttrInfo+x)->dwADsType) { case ADSTYPE_DN_STRING: case ADSTYPE_CASE_EXACT_STRING: case ADSTYPE_CASE_IGNORE_STRING: case ADSTYPE_PRINTABLE_STRING: { // If the returned value is multi-valued //(which it is when using ranging), // then loop through all the values in //the multi-value for (DWORD dwVal = 0 ; dwVal < (pAttrInfo+x)->dwNumValues; dwVal++) { // Print the values in the multi-valued //return data wprintf(L"%d: %s = %s\n",dAttribsGotten,(pAttrInfo+x)->pszAttrName,((pAttrInfo+x)->pADsValues+dwVal)->CaseIgnoreString); // Increment some counters for checking // whether LESS data was // returned than was asked for (which // means you are done) dAttribsGotten++; iAttribsGottenLastSrch++; } break; } default: wprintf(L"%d: %s = !!UnHandled Type!!\n",dAttribsGotten,(pAttrInfo+x)->pszAttrName); FreeADsMem( pAttrInfo ); pAttrInfo = NULL; } } } if (FAILED(hr) || hr ==S_ADS_NOMORE_ROWS || iAttribsGottenLastSrch== 0 || iAttribsGottenLastSrch< iNumToDisplayAtATime ) break; // Increment the range counter, so the next string that is // built will get the next range iRange += iNumToDisplayAtATime; } // Use FreeADsMem for all memory obtained from ADSI call return S_OK; }
The following code fragment contains a subroutine that uses ranging to retrieve the members of a group:
'//////////////////////////////////////////////////////////////////////////////////////////////////// ' PrintAttributeWithRanging() - Uses ADO to read an attribute with ADSI Ranging ' ' Parameters ' ' oDirObject pDirObject As IDirectoryObject - Object from which the attribute will be read ' ByVal sAttribute As String - Name of the attribute ' ByVal iNumToDisplayAtATime As Integer - Number of Attributes to retrieve at a time ' ' Sub PrintAttributeWithRanging(oDirObject As IDirectoryObject, ByVal sAttribute As String, ByVal iNumToDisplayAtATime As Integer) Dim iIndex As Integer iIndex = 0 Dim j, i Dim con As New Connection, rs As New Recordset Dim Com As New Command Dim oIADs As IADs Dim sAdsPathRoot As String ' Get the LDAP path to the passed in object sAdsPathRoot = GetAdsPath(oDirObject) 'Open a Connection object con.Provider = "ADsDSOObject" '----------------------------------------------------------------- ' To be authenticated using alternate credentials ' use connection properties of User ID and Password '----------------------------------------------------------------- ' con.Properties("User ID") = "Administrator" ' con.Properties("Password") = "" ' Open the connection con.Open "Active Directory Provider" ' Create a command object on this connection Set Com.ActiveConnection = con Dim iNumLastReturned As Integer Dim iTotalAttribs As Integer Dim iRange As Integer iTotalAttribs = 0 iRange = 0 Do ' set the query string using SQL Dialect Com.CommandText = "SELECT '" & sAttribute & ";Range=" & Trim(Str(iRange)) & "-" & Trim(Str(iRange + iNumToDisplayAtATime)) & "' FROM '" & sAdsPathRoot & "' WHERE CN='*'" ' Tell the user what the search filter is DisplayMessage "Search Filter = " & Com.CommandText '--------------------------------------------------- ' Or you can use LDAP Dialect, for example, '--------------------------------------------------- ' Ex Com.CommandText = "<LDAP://Microsoft1/dc=Microsoft,DC=com>;(objectClass=*);name" ' For LDAP Dialect, the valid search scope are base, oneLevel and subtree ' Com.CommandText = "<" & adDomainPath & ">;(objectClass=*);name;subtree" ' For LDAP Dialect (<LDAP:...>), there is no way to specify sort order in the string, ' However, you can use this SORT ON property to specify sort order. ' for SQL Dialect you can use ORDER BY in the SQL Statement ' Ex. Com.Properties("Sort On") = "Name" 'Set the preferences for Search Com.Properties("Page Size") = 1000 Com.Properties("Timeout") = 30 'seconds Com.Properties("searchscope") = ADS_SCOPE_BASE Com.Properties("Chase referrals") = ADS_CHASE_REFERRALS_EXTERNAL Com.Properties("Cache Results") = False ' do not cache the result, it results in less memory requirements 'Execute the query Set rs = Com.Execute ' Tell the user how many rows DisplayMessage "Returned " & Str(rs.RecordCount) & " rows" iNumLastReturned = 0 ' Navigate the record set If Not rs.EOF Then rs.MoveFirst End If Dim f As Field Dim iCount As Integer iCount = 0 On Error Resume Next While Not rs.EOF For Each f In rs.Fields ' Is the value a Variant Array? If TypeName(f.Value) = "Variant()" Then Dim v As Variant For Each v In f.Value DisplayMessage f.Name & " (" & iTotalAttribs & ")" & "-" & v iCount = iCount + 1 iNumLastReturned = iNumLastReturned + 1 iTotalAttribs = iTotalAttribs + 1 Next v Else ' Otherwise display a single valued attribute DisplayMessage f.Name & f.Value 'rs.Fields("AdsPath") End If Next f rs.MoveNext Wend Set rs = Nothing Set f = Nothing iRange = iRange + iNumToDisplayAtATime Loop While iNumLastReturned > 0 End Sub