Executando uma consulta de escopo de atributo

A consulta de escopo de atributo é uma preferência de pesquisa que permite que uma pesquisa de atributos com valor de nome distinto de um objeto seja executada. O atributo a ser pesquisado pode ser único ou com vários valores, mas deve ser do tipo ADS_DN_STRING . Quando a pesquisa for executada, o ADSI enumerará os valores de nome distinto do atributo e executará a pesquisa nos objetos representados pelos nomes distintos. Por exemplo, se uma pesquisa com escopo de atributo for executada do atributo membro de um objeto de grupo, o ADSI enumerará os nomes distintos no atributo de membro e pesquisará em cada um dos membros do grupo os critérios de pesquisa especificados.

Se uma consulta com escopo de atributo for executada em um atributo que não seja do tipo ADS_DN_STRING, a pesquisa falhará. A consulta com escopo de atributo também requer que a preferência ADS_SEARCHPREF_SEARCH_SCOPE seja definida como ADS_SCOPE_BASE. A preferência ADS_SEARCHPREF_SEARCH_SCOPE será definida automaticamente como ADS_SCOPE_BASE, mas se a preferência ADS_SEARCHPREF_SEARCH_SCOPE for definida como qualquer outro valor, IDirectorySearch::SetSearchPreference falhará com E_ADS_BAD_PARAMETER.

Os resultados de uma consulta de escopo de atributo podem abranger vários servidores e um servidor pode não retornar todos os dados solicitados para todas as linhas retornadas. Se isso ocorrer, quando a última linha for recuperada chamando IDirectorySearch::GetNextRow ou IDirectorySearch::GetFirstRow, o ADSI retornará S_ADS_ERRORSOCCURRED em vez de S_ADS_NOMORE_ROWS.

Para especificar uma consulta de escopo de atributo, defina uma opção de pesquisa ADS_SEARCHPREF_ATTRIBUTE_QUERY com um valor de ADSTYPE_CASE_IGNORE_STRING definido como lDAPDisplayName do atributo a ser pesquisado na matriz ADS_SEARCHPREF_INFO passada para o método IDirectorySearch::SetSearchPreference . Essa operação é mostrada no exemplo de código a seguir.

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

O exemplo de código a seguir mostra como usar a opção de pesquisa 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;
}

Quando essa pesquisa é executada e os resultados são enumerados, ela retornará o nome, o número de telefone e o número do escritório de todos os objetos de usuário contidos na lista de atributos de membro do grupo.

Tratamento de erros: os resultados de uma consulta de escopo de atributo podem abranger vários servidores e um servidor pode não retornar todos os dados solicitados para todas as linhas retornadas. Se isso ocorrer, quando a última linha for recuperada chamando GetNextRow ou GetFirstRow, o ADSI retornará S_ADS_ERRORSOCCURRED, em vez de S_ADS_NOMORE_ROWS.