Énumération des contrôleurs de domaine

Dans les versions antérieures de Windows, une application ne pouvait obtenir qu’un seul contrôleur de domaine dans un domaine en appelant DsGetDcName. Il n’y avait aucun moyen de prédire quel contrôleur de domaine serait récupéré ou d’obtenir une liste des contrôleurs de domaine. Windows permet à une application d’énumérer les contrôleurs de domaine dans un domaine à l’aide des fonctions DsGetDcOpen, DsGetDcNext et DsGetDcClose .

Pour énumérer un contrôleur de domaine, appelez DsGetDcOpen. Cette fonction accepte les paramètres qui définissent le domaine à énumérer et d’autres options d’énumération. DsGetDcOpen fournit un handle de contexte d’énumération de domaine qui est utilisé pour identifier l’opération d’énumération lorsque DsGetDcNext et DsGetDcClose sont appelés.

La fonction DsGetDcNext est appelée avec le handle de contexte d’énumération de domaine pour récupérer le contrôleur de domaine suivant dans l’énumération. La première fois que cette fonction est appelée, le premier contrôleur de domaine de l’énumération est récupéré. La deuxième fois que cette fonction est appelée, le deuxième contrôleur de domaine de l’énumération est récupéré. Ce processus est répété jusqu’à ce que DsGetDcNext retourne ERROR_NO_MORE_ITEMS, qui indique la fin de l’énumération.

La fonction DsGetDcNext énumère les contrôleurs de domaine dans deux groupes. Le premier groupe contient les contrôleurs de domaine qui couvrent le site de l’ordinateur où la fonction est exécutée, et le second groupe contient les contrôleurs de domaine qui ne couvrent pas le site de l’ordinateur sur lequel la fonction est exécutée. Si l’indicateur DS_NOTIFY_AFTER_SITE_RECORDS est spécifié dans le paramètre OptionFlags dans DsGetDcOpen, la fonction DsGetDcNext retourne ERROR_FILEMARK_DETECTED une fois tous les contrôleurs de domaine spécifiques au site récupérés. DsGetDcNext commence ensuite à énumérer le deuxième groupe, qui contient tous les contrôleurs de domaine du domaine, y compris les contrôleurs de domaine spécifiques au site contenus dans le premier groupe.

Les contrôleurs de domaine qui gèrent le site de l’ordinateur sur lequel la fonction est exécutée sont d’abord énumérés, suivis des contrôleurs de domaine qui ne couvrent pas le site de l’ordinateur sur lequel la fonction est exécutée. Un contrôleur de domaine couvre un site si le contrôleur de domaine est configuré pour résider dans ce site ou si le contrôleur de domaine réside dans un site le plus proche du site en question en termes de coût de liaison entre sites configuré. S’il existe des contrôleurs de domaine dans le groupe de contrôleurs de domaine qui couvrent et le groupe de contrôleurs de domaine qui ne couvrent pas le site de l’ordinateur, les contrôleurs de domaine sont retournés dans le groupe dans l’ordre de leurs priorités et pondérations configurées qui sont spécifiées dans DNS. Les contrôleurs de domaine qui ont une priorité numérique inférieure sont d’abord retournés au sein d’un groupe. Si, dans un groupe lié au site, il existe un sous-groupe de plusieurs contrôleurs de domaine avec la même priorité, les contrôleurs de domaine sont retournés dans un ordre aléatoire pondéré où les contrôleurs de domaine avec un poids plus élevé ont plus de probabilité d’être retournés en premier. Les sites, les priorités et les pondérations sont configurés par l’administrateur de domaine pour obtenir des performances efficaces et un équilibrage de charge entre plusieurs contrôleurs de domaine disponibles dans le domaine. Pour cette raison, les applications qui utilisent les fonctions DsGetDcOpen/DsGetDcNext/DsGetDcClose tirent automatiquement parti de ces optimisations.

Lorsque l’énumération est terminée ou n’est plus nécessaire, l’énumération doit être fermée en appelant DsGetDcClose avec le handle de contexte d’énumération de domaine.

Pour réinitialiser l’énumération, il est nécessaire de fermer l’énumération actuelle en appelant DsGetDcClose , puis de rouvrir l’énumération en appelant à nouveau DsGetDcOpen .

Exemple

L’exemple de code suivant montre comment utiliser ces fonctions pour énumérer les contrôleurs de domaine dans le domaine local.

DWORD dwRet;
PDOMAIN_CONTROLLER_INFO pdcInfo;

// Get a domain controller for the domain this computer is on.
dwRet = DsGetDcName(NULL, NULL, NULL, NULL, 0, &pdcInfo);
if(ERROR_SUCCESS == dwRet)
{
    HANDLE hGetDc;
    
    // Open the enumeration.
    dwRet = DsGetDcOpen(    pdcInfo->DomainName,
                            DS_NOTIFY_AFTER_SITE_RECORDS,
                            NULL,
                            NULL,
                            NULL,
                            0,
                            &hGetDc);
    if(ERROR_SUCCESS == dwRet)
    {
        LPTSTR pszDnsHostName;

        /*
        Enumerate each domain controller and print its name to the 
        debug window.
        */
        while(TRUE)
        {
            ULONG ulSocketCount;
            LPSOCKET_ADDRESS rgSocketAddresses;

            dwRet = DsGetDcNext(
                hGetDc, 
                &ulSocketCount, 
                &rgSocketAddresses, 
                &pszDnsHostName);
            
            if(ERROR_SUCCESS == dwRet)
            {
                OutputDebugString(pszDnsHostName);
                OutputDebugString(TEXT("\n"));
                
                // Free the allocated string.
                NetApiBufferFree(pszDnsHostName);

                // Free the socket address array.
                LocalFree(rgSocketAddresses);
            }
            else if(ERROR_NO_MORE_ITEMS == dwRet)
            {
                // The end of the list has been reached.
                break;
            }
            else if(ERROR_FILEMARK_DETECTED == dwRet)
            {
                /*
                DS_NOTIFY_AFTER_SITE_RECORDS was specified in 
                DsGetDcOpen and the end of the site-specific 
                records was reached.
                */
                OutputDebugString(
                  TEXT("End of site-specific domain controllers\n"));
                continue;
            }
            else
            {
                // Some other error occurred.
                break;
            }
        }
        
        // Close the enumeration.
        DsGetDcClose(hGetDc);
    }
    
    // Free the DOMAIN_CONTROLLER_INFO structure. 
    NetApiBufferFree(pdcInfo);
}