Jak niezawodnie i szybko uzyskać adres MAC karty sieciowej, podając identyfikator instancji urządzenia
Dawaćidentyfikator instancji urządzenia dla karty sieciowej chciałbym poznać jej adres MAC. Przykładowy identyfikator instancji urządzenia w moim systemie dla zintegrowanej karty Intel Gigabit:
PCI\VEN_8086&DEV_10CC&SUBSYS_00008086&REV_00\3&33FD14CA&0&C8
Jak dotąd algorytm, z którego korzystałem, działa w następujący sposób:
PołączenieSetupDiGetClassDevs
zDIGCF_DEVICEINTERFACE
.PołączenieSetupDiEnumDeviceInfo
uzyskać zwrócone urządzenie w aSP_DEVINFO_DATA
.PołączenieSetupDiEnumDeviceInterfaces
zGUID_NDIS_LAN_CLASS
aby uzyskać interfejs urządzenia.PołączenieSetupDiGetDeviceInterfaceDetail
dla tego zwróconego interfejsu urządzenia. Dzięki temu otrzymamy ścieżkę urządzenia jako ciąg znaków:\\?\pci#ven_8086&dev_10cc&subsys_00008086&rev_00#3&33fd14ca&0&c8#{ad498944-762f-11d0-8dcb-00c04fc3358c}\{28fd5409-15bd-4c06-b62f-004d3a06f852}
W tym momencie mamy adres do interfejsu sterownika karty sieciowej. Otwórz toCreateFile
wykorzystanie wyniku z # 4.PołączenieDeviceIoControl
zIOCTL_NDIS_QUERY_GLOBAL_STATS
i OID zOID_802_3_PERMANENT_ADDRESS
aby uzyskać adres MAC.Zwykle działa i jest z powodzeniem używana na dość dużej liczbie maszyn. Wygląda jednak na to, że kilka wybranych komputerów ma sterowniki sieciowe, które nie reagują poprawnie naDeviceIoControl
żądanie w kroku 6; problem utrzymuje się nawet po zaktualizowaniu sterowników karty sieciowej do najnowszej. Są to nowsze komputery z systemem Windows 7. Konkretnie,DeviceIoControl
kończy się pomyślnie, ale zwraca zero bajtów zamiast oczekiwanych sześciu bajtów zawierających adres MAC.
Wskazówka wydaje się być na stronie MSDN dlaIOCTL_NDIS_QUERY_GLOBAL_STATS
:
Ten IOCTL będzie przestarzały w późniejszych wersjach systemu operacyjnego. Należy używać interfejsów WMI do wyszukiwania informacji o sterowniku miniportu. Aby uzyskać więcej informacji, zobacz NDIS Support for WMI.
- być może nowsze sterowniki kart sieciowych nie wdrażają już tego IOCTL?
Więc jak mam to osiągnąć? Czy możliwe jest niedopatrzenie w moim podejściu i robię coś nie tak? A może muszę przyjąć znacznie inne podejście? Niektóre alternatywne podejścia obejmują:
PytanieWin32_NetworkAdapter
Klasa WMI: dostarcza potrzebnych informacji, ale została odrzucona z powodu strasznej wydajności. WidziećSzybki zamiennik klasy WMI Win32_NetworkAdapter do pobierania adresu MAC komputera lokalnegoPytanieMSNdis_EthernetPermanentAddress
Klasa WMI: wydaje się być zamiennikiem WMI dlaIOCTL_NDIS_QUERY_GLOBAL_STATS
i pyta OID bezpośrednio ze sterownika - a ten działa na kłopotliwym sterowniku sieci. Niestety, zwrócone instancje klasy dostarczają tylko adres MAC iInstanceName
, który jest zlokalizowanym ciągiem jakIntel(R) 82567LM-2 Gigabit Network Connection
. ZapytanieMSNdis_EnumerateAdapter
daje listę, która odnosi się doInstanceName
do aDeviceName
, lubić\DEVICE\{28FD5409-15BD-4C06-B62F-004D3A06F852}
. Nie jestem pewien, jak przejść odDeviceName
do identyfikatora instancji urządzenia typu plug-and-play (PCI\VEN_8086......
).PołączenieGetAdaptersAddresses
lubGetAdaptersInfo
(przestarzałe). Jedynym nielokalnym identyfikatorem, który mogę znaleźć w wartości zwracanej, jest nazwa adaptera, która jest łańcuchem jak{28FD5409-15BD-4C06-B62F-004D3A06F852}
- tak samo jakDeviceName
zwrócone przez klasy WMI NDIS. Tak więc nie mogę znaleźć sposobu na powiązanie go z identyfikatorem instancji urządzenia. Nie jestem pewien, czy to zadziałałoby w 100% przypadków - np. dla adapterów bez skonfigurowanego protokołu TCP / IP.Metoda NetBIOS: wymaga skonfigurowania określonych protokołów na karcie, aby nie działała w 100%. Ogólnie wydaje się, że jest to hack-ish, a nie sposób na powiązanie z ID instancji urządzenia, o którym wiem. Odrzuciłem to podejście.Metoda generowania UUID: odrzucona z powodów, których nie będę tutaj omawiać.Wygląda na to, że gdybym mógł znaleźć sposób na uzyskanie „GUID” dla karty z ID instancji urządzenia, byłbym na dobrej drodze z jednym z pozostałych dwóch sposobów robienia rzeczy. Ale jeszcze się nie zorientowałem. W przeciwnym razie podejście WMI NDIS wydaje się najbardziej obiecujące.
Pobieranie listy kart sieciowych i adresów MAC jest łatwe i istnieje kilka sposobów na to. Wykonywanie tego w szybki sposób, który pozwala mi powiązać go z identyfikatorem instancji urządzenia, jest najwyraźniej trudne ...
EDYTOWAĆ: Przykładowy kod wywołania IOCTL, jeśli pomaga komuś (zignoruj wyciekły uchwyt 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();
}
Kod kończy się niepowodzeniem, drukowanie:
GetMACAddress: invalid address length of 0.
Zatem DeviceIoControl zwraca niezerową wartość wskazującą na sukces, ale następnie zwraca zero bajtów.