Realización de una consulta de ámbito de atributo

La consulta de ámbito de atributo es una preferencia de búsqueda que permite realizar una búsqueda de los atributos con valores de nombre distintivos de un objeto. El atributo que se va a buscar puede ser de un solo valor o multivalor, pero debe ser del tipo ADS_DN_STRING . Cuando se realiza la búsqueda, ADSI enumerará los valores de nombre distintivos del atributo y realizará la búsqueda en los objetos representados por los nombres distintivos. Por ejemplo, si se realiza una búsqueda con ámbito de atributo del atributo miembro de un objeto de grupo, ADSI enumerará los nombres distintivos en el atributo miembro y buscará en cada uno de los miembros del grupo los criterios de búsqueda especificados.

Si se realiza una consulta con ámbito de atributo en un atributo que no es de tipo ADS_DN_STRING, se producirá un error en la búsqueda. La consulta con ámbito de atributo también requiere que la preferencia de ADS_SEARCHPREF_SEARCH_SCOPE se establezca en ADS_SCOPE_BASE. La preferencia de ADS_SEARCHPREF_SEARCH_SCOPE se establecerá automáticamente en ADS_SCOPE_BASE, pero si la preferencia de ADS_SEARCHPREF_SEARCH_SCOPE está establecida en cualquier otro valor, IDirectorySearch::SetSearchPreference producirá un error con E_ADS_BAD_PARAMETER.

Los resultados de una consulta de ámbito de atributo pueden abarcar varios servidores y es posible que un servidor no devuelva todos los datos solicitados para todas las filas devueltas. Si esto ocurre, cuando se recupera la última fila llamando a IDirectorySearch::GetNextRow o IDirectorySearch::GetFirstRow, ADSI devolverá S_ADS_ERRORSOCCURRED en lugar de S_ADS_NOMORE_ROWS.

Para especificar una consulta de ámbito de atributo, establezca una opción de búsqueda ADS_SEARCHPREF_ATTRIBUTE_QUERY con un valor de ADSTYPE_CASE_IGNORE_STRING establecido en lDAPDisplayName del atributo para buscar en la matriz de ADS_SEARCHPREF_INFO pasada al método IDirectorySearch::SetSearchPreference . Esta operación se muestra en el ejemplo de código siguiente.

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

En el ejemplo de código siguiente se muestra cómo usar la opción de búsqueda 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;
}

Cuando se ejecuta esta búsqueda y se enumeran los resultados, devolvería el nombre, el número de teléfono y el número de oficina de todos los objetos de usuario contenidos en la lista de atributos de miembro del grupo.

Control de errores: los resultados de una consulta de ámbito de atributo pueden abarcar varios servidores y es posible que un servidor no devuelva todos los datos solicitados para todas las filas devueltas. Si esto ocurre, cuando se recupera la última fila llamando a GetNextRow o GetFirstRow, ADSI devolverá S_ADS_ERRORSOCCURRED, en lugar de S_ADS_NOMORE_ROWS.