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.

questionAnswers(2)

yourAnswerToTheQuestion