枚举域控制器
在早期版本的 Windows 中,应用程序只能通过调用 DsGetDcName 在域中获取单个域控制器。 无法预测要检索的域控制器或获取域控制器列表。 Windows 允许应用程序使用 DsGetDcOpen、DsGetDcNext 和 DsGetDcClose 函数枚举域中的域控制器。
若要枚举域控制器,请调用 DsGetDcOpen。 此函数采用用于定义要枚举的域和其他枚举选项的参数。 DsGetDcOpen 提供域枚举上下文句柄,用于在调用 DsGetDcNext 和 DsGetDcClose 时标识枚举操作。
使用域枚举上下文句柄调用 DsGetDcNext 函数,以检索枚举中的下一个域控制器。 首次调用此函数时,将检索枚举中的第一个域控制器。 第二次调用此函数时,将检索枚举中的第二个域控制器。 此过程将重复,直到 DsGetDcNext 返回 ERROR_NO_MORE_ITEMS,指示枚举的末尾。
DsGetDcNext 函数将枚举两个组中的域控制器。 第一个组包含涵盖在其中执行函数的计算机站点的域控制器,第二个组包含不涵盖在其中执行函数的计算机站点的域控制器。 如果在 DsGetDcOpen 的 OptionFlags 参数中指定了 DS_NOTIFY_AFTER_SITE_RECORDS 标志,则检索到所有特定于站点的域控制器后,DsGetDcNext 函数将返回 ERROR_FILEMARK_DETECTED。 然后,DsGetDcNext 将开始枚举第二个组,该组包含域中的所有域控制器,包括第一组中包含的特定于站点的域控制器。
首先枚举处理在其中执行函数的计算机站点的域控制器,然后枚举不涵盖在其中执行函数的计算机站点的域控制器。 如果将域控制器配置为驻留在该站点中,或者域控制器位于就配置的站点间链路成本而言,离站点最近的站点中,则表示域控制器涵盖站点。 如果涵盖的两组域控制器包含任何域控制器,以及不涵盖计算机站点的域控制器组,则会按照 DNS 中指定的已配置优先级和权重在组中返回域控制器。 首先在组中返回具有较低数值优先级的域控制器。 如果站点相关组中有多个具有相同优先级的域控制器的子组,则会按加权随机顺序返回域控制器,其中首先返回具有较高权重的域控制器的可能性更大。 站点、优先级和权重由域管理员配置,以在域中提供的多个域控制器之间实现有效的性能和负载均衡。 因此,使用 DsGetDcOpen/DsGetDcNext/DsGetDcClose 函数的应用程序会自动利用这些优化。
当枚举完成或不再需要枚举时,必须使用域枚举上下文句柄调用 DsGetDcClose 来关闭枚举。
若要重置枚举,必须通过调用 DsGetDcClose 关闭当前枚举,然后再次调用 DsGetDcOpen 重新打开枚举。
示例
以下代码示例演示如何使用这些函数枚举本地域中的域控制器。
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);
}