Enumerando controladores de domínio

Em versões anteriores do Windows, um aplicativo só podia obter um único controlador de domínio em um domínio chamando DsGetDcName. Não havia como prever qual controlador de domínio seria recuperado ou obter uma lista dos controladores de domínio. O Windows permite que um aplicativo enumere os controladores de domínio em um domínio usando as funções DsGetDcOpen, DsGetDcNext e DsGetDcClose.

Para enumerar um controlador de domínio, chame DsGetDcOpen. Essa função usa parâmetros que definem o domínio a ser enumerado e outras opções de enumeração. DsGetDcOpen fornece um identificador de contexto de enumeração de domínio que é usado para identificar a operação de enumeração quando DsGetDcNext e DsGetDcClose são chamados.

A função DsGetDcNext é chamada com o identificador de contexto de enumeração de domínio para recuperar o próximo controlador de domínio na enumeração. Na primeira vez que essa função é chamada, o primeiro controlador de domínio na enumeração é recuperado. Na segunda vez que essa função é chamada, o segundo controlador de domínio na enumeração é recuperado. Esse processo é repetido até que DsGetDcNext retorne ERROR_NO_MORE_ITEMS, que indica o final da enumeração.

A função DsGetDcNext enumerará os controladores de domínio em dois grupos. O primeiro grupo contém os controladores de domínio que cobrem o site do computador onde a função é executada e o segundo grupo contém os controladores de domínio que não cobrem o site do computador onde a função é executada. Se o sinalizador DS_NOTIFY_AFTER_SITE_RECORDS for especificado no parâmetro OptionFlags em DsGetDcOpen, a função DsGetDcNext retornará ERROR_FILEMARK_DETECTED depois que todos os controladores de domínio específicos do site tiverem sido recuperados. DsGetDcNext começará a enumerar o segundo grupo, que contém todos os controladores de domínio no domínio, incluindo os controladores de domínio específicos do site contidos no primeiro grupo.

Os controladores de domínio que manipulam o site do computador onde a função é executada são enumerados primeiro, seguidos pelos controladores de domínio que não cobrem o site do computador onde a função é executada. Diz-se que um controlador de domínio cobre um site se o controlador de domínio estiver configurado para residir nesse site ou se o controlador de domínio residir em um site mais próximo do site em questão em termos do custo de link entre sites configurado. Se houver controladores de domínio no grupo de controladores de domínio que abrangem e no grupo de controladores de domínio que não abrangem o site do computador, os controladores de domínio serão retornados dentro do grupo na ordem de suas prioridades e pesos configurados especificados no DNS. Os controladores de domínio que têm prioridade numérica mais baixa são retornados dentro de um grupo primeiro. Se dentro de um grupo relacionado ao site houver um subgrupo de vários controladores de domínio com a mesma prioridade, os controladores de domínio serão retornados em uma ordem aleatória ponderada em que os controladores de domínio com peso mais alto têm mais probabilidade de serem retornados primeiro. Os sites, prioridades e pesos são configurados pelo administrador do domínio para obter desempenho efetivo e balanceamento de carga entre vários controladores de domínio disponíveis no domínio. Devido a isso, os aplicativos que usam as funções DsGetDcOpen/DsGetDcNext/DsGetDcClose aproveitam automaticamente essas otimizações.

Quando a enumeração estiver concluída ou não for mais necessária, a enumeração deverá ser fechada chamando DsGetDcClose com o identificador de contexto de enumeração de domínio.

Para redefinir a enumeração, é necessário fechar a enumeração atual chamando DsGetDcClose e, em seguida, reabrir a enumeração chamando DsGetDcOpen novamente.

Exemplo

O exemplo de código a seguir mostra como usar essas funções para enumerar os controladores de domínio no domínio 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);
}