执行属性范围查询
属性范围查询是一种搜索首选项,可以对对象的可分辨名称值属性进行搜索。 要搜索的属性可以是单值或多值,但必须是 ADS_DN_STRING 类型。 执行搜索时,ADSI 将枚举属性的可分辨名称值,并在可分辨名称所代表的对象上执行搜索。 例如,如果对组对象的 member 属性执行属性范围搜索,ADSI 将枚举 member 属性中的可分辨名称,并根据指定的搜索条件搜索组中的每个成员。
如果对非 ADS_DN_STRING 类型的属性执行了属性作用域查询,则搜索将失败。 属性作用域查询还要求将 ADS_SEARCHPREF_SEARCH_SCOPE 首选项设置为 ADS_SCOPE_BASE。 ADS_SEARCHPREF_SEARCH_SCOPE 首选项将自动设置为ADS_SCOPE_BASE,但如果 ADS_SEARCHPREF_SEARCH_SCOPE 首选项设置为任何其他值,则 IDirectorySearch::SetSearchPreference 将以 E_ADS_BAD_PARAMETER 失败。
属性范围查询的结果可能会跨越多个服务器,而一个服务器可能不会返回所请求的所有行的所有数据。 如果出现这种情况,在调用 IDirectorySearch::GetNextRow 或 IDirectorySearch::GetFirstRow 检索最后一行时,ADSI 将返回 S_ADS_ERRORSOCCURRED 而不是 S_ADS_NOMORE_ROWS。
要指定属性范围查询,请在传递给 IDirectorySearch::SetSearchPreference 方法的 ADS_SEARCHPREF_INFO 数组中设置 ADS_SEARCHPREF_ATTRIBUTE_QUERY 搜索选项,并将 ADSTYPE_CASE_IGNORE_STRING 值设置为要搜索的属性的 lDAPDisplayName。 下面的代码示例对此操作进行了演示。
ADS_SEARCHPREF_INFO SearchPref;
SearchPref.dwSearchPref = ADS_SEARCHPREF_ATTRIBUTE_QUERY;
SearchPref.vValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
SearchPref.vValue.Boolean = L"member";
下面的代码示例展示了如何使用 ADS_SEARCHPREF_ATTRIBUTE_QUERY 搜索选项。
/***************************************************************************
SearchGroupMembers()
Searches the members of a group that are of type user and prints each
user's cn and distinguishedName values to the console.
Parameters:
pwszGroupDN - Contains the distinguished name of the group whose
members will be searched.
***************************************************************************/
HRESULT SearchGroupMembers(LPCWSTR pwszGroupDN)
{
HRESULT hr;
CComPtr<IDirectorySearch> spSearch;
CComBSTR sbstrADsPath;
// Bind to the group and get the IDirectorySearch interface.
sbstrADsPath = "LDAP://";
sbstrADsPath += pwszGroupDN;
hr = ADsOpenObject(sbstrADsPath,
NULL,
NULL,
ADS_SECURE_AUTHENTICATION,
IID_IDirectorySearch,
(void**)&spSearch);
if(FAILED(hr))
{
return hr;
}
ADS_SEARCHPREF_INFO SearchPrefs[1];
// Set the ADS_SEARCHPREF_ATTRIBUTE_QUERY search preference.
SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_ATTRIBUTE_QUERY;
SearchPrefs[0].vValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
SearchPrefs[0].vValue.CaseIgnoreString = L"member";
// Set the search preferences.
hr = spSearch->SetSearchPreference(SearchPrefs, sizeof(SearchPrefs)/sizeof(ADS_SEARCHPREF_INFO));
if(FAILED(hr))
{
return hr;
}
ADS_SEARCH_HANDLE hSearch;
// Create the search filter.
LPWSTR pwszSearchFilter = L"(&(objectClass=user))";
// Set attributes to return.
LPWSTR rgpwszAttributes[] = {L"cn", L"distinguishedName"};
DWORD dwNumAttributes = sizeof(rgpwszAttributes)/sizeof(LPWSTR);
// Execute the search.
hr = spSearch->ExecuteSearch(pwszSearchFilter,
rgpwszAttributes,
dwNumAttributes,
&hSearch);
if(FAILED(hr))
{
return hr;
}
// Get the first result row.
hr = spSearch->GetFirstRow(hSearch);
while(S_OK == hr)
{
ADS_SEARCH_COLUMN col;
// Enumerate the retrieved attributes.
for(DWORD i = 0; i < dwNumAttributes; i++)
{
hr = spSearch->GetColumn(hSearch, rgpwszAttributes[i], &col);
if(SUCCEEDED(hr))
{
switch(col.dwADsType)
{
case ADSTYPE_DN_STRING:
wprintf(L"%s: %s\n\n", rgpwszAttributes[i], col.pADsValues[0].DNString);
break;
case ADSTYPE_CASE_IGNORE_STRING:
wprintf(L"%s: %s\n\n", rgpwszAttributes[i], col.pADsValues[0].CaseExactString);
break;
default:
break;
}
// Free the column.
spSearch->FreeColumn(&col);
}
}
// Get the next row.
hr = spSearch->GetNextRow(hSearch);
}
// Close the search handle to cleanup.
hr = spSearch->CloseSearchHandle(hSearch);
return hr;
}
执行此搜索并对结果进行枚举后,将返回组的 member 属性列表中包含的所有用户对象的 name、telephone number 和 office number。
错误处理:属性范围查询的结果可能会跨越多个服务器,而一个服务器可能不会返回所请求的所有行的所有数据。 如果出现这种情况,在调用 GetNextRow 或 GetFirstRow 检索最后一行时,ADSI 将返回 S_ADS_ERRORSOCCURRED 而不是 S_ADS_NOMORE_ROWS。