ネットワーク カードのデバイス インスタンス IDが与えられた場合、その MAC アドレスを知りたいです。内蔵 Intel ギガビット カードのシステムでのデバイス インスタンス ID の例:
PCI\VEN_8086&DEV_10CC&SUBSYS_00008086&REV_00\3&33FD14CA&0&C8
これまでのところ、私が使用したアルゴリズムは次のように機能します。
SetupDiGetClassDevs
で呼び出しDIGCF_DEVICEINTERFACE
ます。- を呼び出し
SetupDiEnumDeviceInfo
て、返されたデバイスを で取得しSP_DEVINFO_DATA
ます。 - で呼び出し
SetupDiEnumDeviceInterfaces
てGUID_NDIS_LAN_CLASS
、デバイス インターフェイスを取得します。 SetupDiGetDeviceInterfaceDetail
この返されたデバイス インターフェイスを呼び出します。これにより、デバイス パスが文字列として取得されます。\\?\pci#ven_8086&dev_10cc&subsys_00008086&rev_00#3&33fd14ca&0&c8#{ad498944-762f-11d0-8dcb-00c04fc3358c}\{28fd5409-15bd-4c06-b62f-004d3a06f852}
- この時点で、ネットワーク カード ドライバーのインターフェイスへのアドレスを取得しています。
CreateFile
#4 の結果を使用して開きます。 - と OID を呼び出し
DeviceIoControl
て、MAC アドレスを取得します。IOCTL_NDIS_QUERY_GLOBAL_STATS
OID_802_3_PERMANENT_ADDRESS
これは通常は機能し、非常に多くのマシンで正常に使用されています。DeviceIoControl
ただし、手順 6の要求に適切に応答しないネットワーク ドライバーを備えたごく少数のマシンが存在するようです。ネットワークカードドライバーを最新に更新した後でも問題は解決しません。これらは、新しい Windows 7 ベースのコンピューターです。具体的には、DeviceIoControl
正常に完了しますが、MAC アドレスを含む予想される 6 バイトではなく、0 バイトを返します。
手がかりはMSDNページにあるようですIOCTL_NDIS_QUERY_GLOBAL_STATS
:
この IOCTL は、以降のオペレーティング システムのリリースでは非推奨になります。ミニポート ドライバー情報を照会するには、WMI インターフェイスを使用する必要があります。詳細については、「WMI の NDIS サポート」を参照してください。
-- おそらく、新しいネットワーク カード ドライバは、この IOCTL を実装していないのでしょうか?
では、どうすればこれを機能させることができますか?私のアプローチに見落としがあり、少し間違ったことをしている可能性はありますか? それとも、もっと別のアプローチを取る必要がありますか? いくつかの代替アプローチには、次のものが含まれているようです。
- クエリ
Win32_NetworkAdapter
WMI クラス: 必要な情報を提供しますが、パフォーマンスがひどいために拒否されました。ローカル コンピューターの MAC アドレスを取得するための Win32_NetworkAdapter WMI クラスの高速置換を参照してください。 - Query
MSNdis_EthernetPermanentAddress
WMI class: WMI の代替と思われるものでIOCTL_NDIS_QUERY_GLOBAL_STATS
、ドライバーから直接 OID を照会します。これは、厄介なネットワーク ドライバーで動作します。残念ながら、返されたクラス インスタンスは、MAC アドレスと、のInstanceName
ようなローカライズされた文字列であるのみを提供しますIntel(R) 82567LM-2 Gigabit Network Connection
。クエリを実行すると、をなどMSNdis_EnumerateAdapter
に関連付けるリストが生成されます。からプラグアンドプレイ デバイス インスタンス ID ( )に移動する方法がわかりません。InstanceName
DeviceName
\DEVICE\{28FD5409-15BD-4C06-B62F-004D3A06F852}
DeviceName
PCI\VEN_8086......
GetAdaptersAddresses
orGetAdaptersInfo
(非推奨) を呼び出します。戻り値で見つけることができる唯一のローカライズされていない識別子はアダプター名です。これは、WMI NDIS クラスによって返されるもの{28FD5409-15BD-4C06-B62F-004D3A06F852}
と同じような文字列です。DeviceName
繰り返しますが、それをデバイス インスタンス ID に関連付ける方法がわかりません。TCP/IP プロトコルが構成されていないアダプターなど、100% の時間でも動作するかどうかはわかりません。- NetBIOS 方式: 特定のプロトコルをカードに設定する必要があるため、100% は機能しません。一般的にはハックっぽいようで、とにかく私が知っているデバイス インスタンス ID に関連付ける方法ではありません。私はこのアプローチを拒否します。
- UUID 生成方法: ここでは詳しく説明しない理由により拒否されました。
デバイス インスタンス ID からカードの "GUID" を取得する方法を見つけることができれば、残りの 2 つの方法のいずれかでうまくいくようです。しかし、私はまだ方法を理解していません。それ以外の場合は、WMI NDIS アプローチが最も有望に思えます。
ネットワーク カードと MAC アドレスのリストを取得するのは簡単で、いくつかの方法があります。デバイス インスタンス ID に関連付けることができる高速な方法でそれを行うのは明らかに難しいです...
編集: 誰かに役立つ場合のIOCTL呼び出しのサンプルコード(リークされたhFileハンドルは無視してください):
HANDLE hFile = CreateFile(dosDevice.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
wcout << "GetMACAddress: CreateFile on " << dosDevice << " failed." << endl;
return MACAddress();
}
BYTE address[6];
DWORD oid = OID_802_3_PERMANENT_ADDRESS, returned = 0;
//this fails too: DWORD oid = OID_802_3_CURRENT_ADDRESS, returned = 0;
if (!DeviceIoControl(hFile, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid), address, 6, &returned, NULL)) {
DWORD err = GetLastError();
wcout << "GetMACAddress: DeviceIoControl on " << dosDevice << " failed." << endl;
return MACAddress();
}
if (returned != 6) {
wcout << "GetMACAddress: invalid address length of " << returned << "." << endl;
return MACAddress();
}
コードは失敗し、次のように出力されます。
GetMACAddress: invalid address length of 0.
そのため、DeviceIoControl は成功を示すゼロ以外を返しますが、その後はゼロ バイトを返します。