Directory Services

Using IADs::GetInfoEx for Range Retrieval

The IADs::GetInfoEx method can be used to retrieve a range of property values. The range of values to retrieve is specified in the property name array passed to the method.

The range specifiers for a property query require the following form:

<property name>;range=<low range>-<high range>
where where <property name> is the ldapDisplayName of the property, <low range> is the zero-based index of the first property value to retrieve and <high range> is the zero-based index of the last property value to retrieve. Zero is used for <low range> to specify the first entry. The wildcard character (*) can be used for <high range> to specify all remaining entries.

The following code example contains a function that shows how to use range retrieval with IADs::GetInfoEx to enumerate the members of a group.

HRESULT EnumGroupWithGetInfoEx(LPCWSTR pwszGroupDN, 
							 LPCWSTR pwszUsername, 
							 LPCWSTR pwszPassword)
{
	if(NULL == pwszGroupDN)
	{
		return E_POINTER;
}

	HRESULT hr;
	IADs *pads;

	hr = ADsOpenObject( pwszGroupDN,
						pwszUsername,
						pwszPassword,
						ADS_SECURE_AUTHENTICATION,
						IID_IADs, 
						(void**)&pads);

	if(SUCCEEDED(hr))
	{
		const DWORD dwStep = 1000;
		DWORD dwLowRange;
		DWORD dwHighRange;
		WCHAR wszAttr[MAX_PATH];
		LPWSTR rgAttrs[1];

		rgAttrs[0] = wszAttr;

		dwLowRange = 0;
		dwHighRange = dwLowRange + (dwStep - 1);

		do
		{
			VARIANT var;

			// Perform this query with the "range=<lowRange>-<highRange>" range.
			wsprintfW(wszAttr, L"member;range=%d-%d", dwLowRange, dwHighRange);

			hr = ADsBuildVarArrayStr(rgAttrs, 1, &var);
			if(SUCCEEDED(hr))
			{
				hr = pads->GetInfoEx(var, 0);
			
				VariantClear(&var);

				if(SUCCEEDED(hr))
				{
					hr = pads->Get(CComBSTR("member"), &var);
					if(SUCCEEDED(hr))
					{
						if(var.vt == (VT_VARIANT | VT_ARRAY))
						{
							VARIANT *pVar;
							long lLBound, lUBound;

							// Get the array of VARIANTs.
							hr = SafeArrayAccessData((SAFEARRAY*)(var.pparray), (void HUGEP* FAR*)&pVar);
							if(SUCCEEDED(hr))
							{
								// Get the bounds for the array.
								hr = SafeArrayGetLBound((SAFEARRAY*)(var.pparray), 1, &lLBound);
								hr = SafeArrayGetUBound((SAFEARRAY*)(var.pparray), 1, &lUBound);

								// Get the number of elements.
								long cElements = lUBound - lLBound + 1;

								// Enumerate the elements.
								for(long i = 0; i < cElements; i++)
								{
									switch(pVar[i].vt)
									{
									case VT_BSTR:
										wprintf(pVar[i].bstrVal); 
										wprintf(L"\n"); 
										break;
								}
							}

								// Release the array.
								SafeArrayUnaccessData((SAFEARRAY*)(var.pparray));
						}
					}
						// This occurs only if one element is retrieved.
						else if (var.vt == VT_BSTR)
						{
							wprintf(var.bstrVal); 
							wprintf(L"\n"); 
					}

						VariantClear(&var);
				}

					// Increment the high and low ranges to query for the next block of objects.
					dwLowRange = dwHighRange + 1;
					dwHighRange = dwLowRange + (dwStep - 1);
			}
		}
	}while(SUCCEEDED(hr));

		pads->Release();
}

	return hr;
}

The following code example contains a function that demonstrates how to use range retrieval with IADs::GetInfoEx to enumerate the members of a group.

Private Sub EnumGroupMembersWithGetInfoEx(strGroupDN As String, strUsername As String, strPassword As String)
	Dim oGroup As IADs
	Dim dso As IADsOpenDSObject

	On Error GoTo quit
	
	strPath = "LDAP://" & strGroupDN

	If "" <> strUsername Then
		' Bind to the group with the specified username and password.
		Set dso = GetObject("LDAP:")
		Set oGroup = dso.OpenDSObject(strPath, strUsername, strPassword, 1)
	Else
		' Bind to the group with the current credentials.
		Set oGroup = GetObject(strPath)
	End If

	' For compatibility with all operating systems, the number of objects
	' retrieved by each query should not exceed 999. The number of objects
	' to retrieve should be as close as possible to 999 to reduce the number
	' of round trips to the server necessary to retrieve the objects.
	rangeStep = 999
	lowRange = 0
	highRange = lowRange + rangeStep

	Do
		' Use the "member;range=<lowRange>-<highRange>" syntax.
		strCommandText = "member;range=" & lowRange & "-" & highRange
		Debug.Print "Current search command: " & strCommandText
	
		' Load the specified range of members into the local cache. This will
		' throw an error if the range exceeds the properties contained in the
		' object. The "On Error GoTo quit" error handler will cause the loop
		' to terminate when this happens.
		On Error GoTo quit
		oGroup.GetInfoEx Array(strCommandText), 0
	
		' Enumerate the retrieved members.
		oMembers = oGroup.Get("member")
		If vbArray And VarType(oMembers) Then
			For Each oMember In oMembers
				' Add the member.
				Debug.Print oMember
				nRetrieved = nRetrieved + 1
			Next
		Else
			' oGroup.Get returned only one member, so add it to the list.
			Debug.Print oMembers
			nRetrieved = nRetrieved + 1
		End If
	
		' Increment the high and low ranges to query for the next block of objects.
		lowRange = highRange + 1
		highRange = lowRange + rangeStep
	Loop While True

quit:
End Sub