给定网络适配器的设备实例ID,我想知道它的MAC地址。 我系统上集成的英特尔千兆网卡的示例设备实例ID:
PCI\VEN_8086&DEV_10CC&SUBSYS_00008086&REV_00\3&33FD14CA&0&C8
到目前为止,我使用的算法工作方式如下:
- 使用
DIGCF_DEVICEINTERFACE
调用SetupDiGetClassDevs
。 - 使用
SetupDiEnumDeviceInfo
获取返回的设备的SP_DEVINFO_DATA
。 - 使用
GUID_NDIS_LAN_CLASS
调用SetupDiEnumDeviceInterfaces
来获取设备接口。 - 为此返回的设备接口调用
SetupDiGetDeviceInterfaceDetail
。这将以字符串形式给我们设备路径:\\?\pci#ven_8086&dev_10cc&subsys_00008086&rev_00#3&33fd14ca&0&c8#{ad498944-762f-11d0-8dcb-00c04fc3358c}\{28fd5409-15bd-4c06-b62f-004d3a06f852}
- 此时我们有了网络卡驱动程序接口的地址。使用 #4 的结果调用
CreateFile
打开它。 - 使用
IOCTL_NDIS_QUERY_GLOBAL_STATS
和 OIDOID_802_3_PERMANENT_ADDRESS
调用DeviceIoControl
来获取 MAC 地址。
MSDN页面IOCTL_NDIS_QUERY_GLOBAL_STATS可能提供了一个线索:
此IOCTL将在以后的操作系统发布中被弃用。您应该使用WMI接口查询miniport驱动程序信息。有关更多信息,请参见NDIS支持WMI。
也许更新的网卡驱动程序不再实现此IOCTL?
那么,我应该如何使它起作用?我的方法是否存在疏忽,我做错了一些事情?还是我需要采取非常不同的方法?一些备选方法似乎包括:
- 查询
Win32_NetworkAdapter
WMI 类:虽然提供所需信息,但由于性能差而被拒绝。请参见Fast replacement for Win32_NetworkAdapter WMI class for getting MAC address of local computer。 - 查询
MSNdis_EthernetPermanentAddress
WMI 类:看起来是IOCTL_NDIS_QUERY_GLOBAL_STATS
的 WMI 替代品,并直接从驱动程序查询 OID - 这一方法适用于有问题的网络驱动程序。不幸的是,返回的类实例仅提供 MAC 地址和InstanceName
,这是一个本地化字符串,如Intel(R) 82567LM-2 Gigabit Network Connection
。查询MSNdis_EnumerateAdapter
会返回一个列表,将InstanceName
和DeviceName
相关联,比如\DEVICE\{28FD5409-15BD-4C06-B62F-004D3A06F852}
。我不知道如何从DeviceName
转换为即插即用设备实例 ID(PCI\VEN_8086......
)。 - 调用
GetAdaptersAddresses
或GetAdaptersInfo
(已弃用)。在返回值中我可以找到的唯一非本地化标识符是适配器名称,这是一个字符串,如{28FD5409-15BD-4C06-B62F-004D3A06F852}
- 与 WMI NDIS 类返回的DeviceName
相同。所以,我仍然不知道如何将其与设备实例 ID 相关联。我也不确定它是否会 100% 生效 - 例如对于未配置 TCP/IP 协议的适配器。 - NetBIOS 方法:需要在卡上设置特定的协议,因此不会 100% 生效。通常看起来很 hack-ish,而且我不知道如何将其与设备实例 ID 相关联。我拒绝采用此方法。
- UUID 生成方法:由于某些原因被拒绝,我将不在此详细阐述。
获取网络卡和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返回非零值表示成功,但随后返回零字节。