Exécution d’une requête d’étendue d’attribut

La requête d’étendue d’attribut est une préférence de recherche qui permet d’effectuer une recherche des attributs de nom unique d’un objet. L’attribut à rechercher peut être unique ou à plusieurs valeurs, mais doit être du type ADS_DN_STRING . Lorsque la recherche est effectuée, ADSI énumère les valeurs de nom unique de l’attribut et effectue la recherche sur les objets représentés par les noms uniques. Par exemple, si une recherche étendue d’attribut est effectuée de l’attribut membre d’un objet de groupe, ADSI énumère les noms uniques dans l’attribut membre et recherche chacun des membres du groupe pour les critères de recherche spécifiés.

Si une requête étendue d’attribut est effectuée sur un attribut qui n’est pas de type ADS_DN_STRING, la recherche échoue. La requête étendue d’attribut nécessite également que la préférence ADS_SEARCHPREF_SEARCH_SCOPE soit définie sur ADS_SCOPE_BASE. La préférence ADS_SEARCHPREF_SEARCH_SCOPE est automatiquement définie sur ADS_SCOPE_BASE, mais si la préférence ADS_SEARCHPREF_SEARCH_SCOPE est définie sur une autre valeur, IDirectorySearch::SetSearchPreference échoue avec E_ADS_BAD_PARAMETER.

Les résultats d’une requête d’étendue d’attribut peuvent s’étendre sur plusieurs serveurs et un serveur ne peut pas retourner toutes les données demandées pour toutes les lignes retournées. Si cela se produit, lorsque la dernière ligne est récupérée en appelant IDirectorySearch::GetNextRow ou IDirectorySearch::GetFirstRow, ADSI retourne S_ADS_ERRORSOCCURRED au lieu de S_ADS_NOMORE_ROWS.

Pour spécifier une requête d’étendue d’attribut, définissez une option de recherche ADS_SEARCHPREF_ATTRIBUTE_QUERY avec une valeur ADSTYPE_CASE_IGNORE_STRING définie sur lDAPDisplayName de l’attribut pour effectuer une recherche dans le tableau ADS_SEARCHPREF_INFO passé à la méthode IDirectorySearch::SetSearchPreference . Cette opération est illustrée dans l’exemple de code suivant.

ADS_SEARCHPREF_INFO SearchPref;
SearchPref.dwSearchPref = ADS_SEARCHPREF_ATTRIBUTE_QUERY;
SearchPref.vValue.dwType = ADSTYPE_CASE_IGNORE_STRING;
SearchPref.vValue.Boolean = L"member";

L’exemple de code suivant montre comment utiliser l’option de recherche 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;
}

Lorsque cette recherche est exécutée et que les résultats sont énumérés, il renvoie le nom, le numéro de téléphone et le numéro de bureau de tous les objets utilisateur contenus dans la liste d’attributs membres du groupe.

Gestion des erreurs : les résultats d’une requête d’étendue d’attribut peuvent s’étendre sur plusieurs serveurs et un serveur ne retourne pas toutes les données demandées pour toutes les lignes retournées. Si cela se produit, lorsque la dernière ligne est récupérée en appelant GetNextRow ou GetFirstRow, ADSI retourne S_ADS_ERRORSOCCURRED, au lieu de S_ADS_NOMORE_ROWS.