ドメインコントローラーの列挙
以前のバージョンのWindowsでは、アプリケーションはDsGetDcNameを呼び出すことによって、ドメイン内の1つのドメインコントローラーのみを取得できました。 取得されるドメインコントローラーを予測したり、ドメインコントローラーの一覧を取得したりする方法はありませんでした。 Windowsでは、アプリケーションはDsGetDcOpen、DsGetDcNext、およびDsGetDcClose関数を使用して、ドメイン内のドメインコントローラーを列挙できます。
ドメインコントローラーを列挙するには、DsGetDcOpenを呼び出します。 この関数は、列挙するドメインとその他の列挙オプションを定義するパラメーターを受け取ります。 DsGetDcOpenには、DsGetDcNextとDsGetDcCloseが呼び出されたときに列挙操作を識別するために使用されるドメイン列挙コンテキストハンドルが用意されています。
DsGetDcNext関数は、ドメイン列挙コンテキストハンドルを使用して呼び出され、列挙体の次のドメインコントローラーを取得します。 この関数が初めて呼び出されたときに、列挙体の最初のドメインコントローラーが取得されます。 この関数が2回目に呼び出されたときに、列挙体の2番目のドメインコントローラーが取得されます。 このプロセスは、列挙体の末尾を示すERROR_NO_MORE_ITEMSがDsGetDcNextによって返されるまで繰り返されます。
DsGetDcNext関数は、2つのグループのドメインコントローラーを列挙します。 最初のグループには、関数が実行されるコンピューターのサイトをカバーするドメインコントローラーが含まれ、2番目のグループには、関数が実行されるコンピューターのサイトをカバーしないドメインコントローラーが含まれます。 DsGetDcOpenのOptionFlagsパラメーターにDS_NOTIFY_AFTER_SITE_RECORDSフラグが指定されている場合、サイト固有のすべてのドメインコントローラーが取得された後、DsGetDcNext関数はERROR_FILEMARK_DETECTEDを返します。 次に、DsGetDcNextは2番目のグループの列挙を開始します。これには、最初のグループに含まれるサイト固有のドメインコントローラーを含む、ドメイン内のすべてのドメインコントローラーが含まれます。
関数が実行されるコンピューターのサイトを処理するドメインコントローラーが最初に列挙され、その後に、関数が実行されるコンピューターのサイトをカバーしないドメインコントローラーが列挙されます。 ドメインコントローラーがそのサイトに存在するように構成されている場合、または構成されたサイト間リンクコストに関して問題のサイトに最も近いサイトにドメインコントローラーが存在する場合、ドメインコントローラーはサイトをカバーすると言います。 コンピューターサイトをカバーするドメインコントローラーのグループと、コンピューターサイトをカバーしないドメインコントローラーのグループの両方にドメインコントローラーがある場合、ドメインコントローラーは、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);
}