TL; DR версия этого вопроса: WMI Win32_NetworkAdapter класс содержит информацию, которая мне нужна, но слишком медленная. Какой более быстрый способ получения информации для столбцов MACAddress, ConfigManagerErrorCode и PNPDeviceID в Windows?
Мне нужно получить информацию для подключенных сетевых адаптеров, чтобы я мог получить MAC-адрес для уникальной идентификации локального компьютера с Microsoft Windows. Класс WMI Win32_NetworkAdapter , похоже, содержит информацию, которую я ищу. Мне действительно нужны столбцы MACAddress, ConfigManagerErrorCode и PNPDeviceID:
- MAC-адрес: MAC-адрес (цель этой операции)
- ConfigManagerErrorCode: позволяет определить, включен адаптер и работает он или нет. (Если он отключен, я должен использовать MAC-адрес, ранее кэшированный моим приложением, если он доступен).
- PNPDeviceID: проверяя префикс «PCI» (и, возможно, другие интерфейсы, если необходимо), я могу отфильтровать нефизические адаптеры, которых на моем Windows 7 несколько (включая виртуальные адаптеры, как для VMware). / VirtualBox).
Мой план состоял в том, чтобы отфильтровать нефизические устройства с использованием PNPDeviceID. Тогда я бы использовал столбец MACAddress для всех оставшихся записей таблицы (сохранение адреса в кеше). Когда устройство отключено (как, возможно, указано ненулевым ConfigManagerErrorCode), а MAC-адрес равен нулю, я могу использовать ранее увиденный MAC-адрес для этого устройства из своего кэша.
Вы можете увидеть содержимое этой таблицы на моем компьютере с Windows 7. Вы можете видеть там тонны мусора, но только одну запись с PNPDeviceID «PCI».
wmic:root\cli>NIC GET Caption, ConfigManagerErrorCode, MACAddress, PNPDeviceID
Caption ConfigManagerErrorCode MACAddress PNPDeviceID
[00000000] WAN Miniport (SSTP) 0 ROOT\MS_SSTPMINIPORT\0000
[00000001] WAN Miniport (IKEv2) 0 ROOT\MS_AGILEVPNMINIPORT\0000
[00000002] WAN Miniport (L2TP) 0 ROOT\MS_L2TPMINIPORT\0000
[00000003] WAN Miniport (PPTP) 0 ROOT\MS_PPTPMINIPORT\0000
[00000004] WAN Miniport (PPPOE) 0 ROOT\MS_PPPOEMINIPORT\0000
[00000005] WAN Miniport (IPv6) 0 ROOT\MS_NDISWANIPV6\0000
[00000006] WAN Miniport (Network Monitor) 0 ROOT\MS_NDISWANBH\0000
[00000007] Intel(R) 82567LM-2 Gigabit Network Connection 0 00:1C:C0:B0:C4:89 PCI\VEN_8086&DEV_10CC&SUBSYS_00008086&REV_00\3&33FD14CA&0&C8
[00000008] WAN Miniport (IP) 0 ROOT\MS_NDISWANIP\0000
[00000009] Microsoft ISATAP Adapter 0 ROOT\*ISATAP\0000
[00000010] RAS Async Adapter 0 20:41:53:59:4E:FF SW\{EEAB7790-C514-11D1-B42B-00805FC1270E}\ASYNCMAC
[00000011] Microsoft Teredo Tunneling Adapter 0 ROOT\*TEREDO\0000
[00000012] VirtualBox Bridged Networking Driver Miniport 0 00:1C:C0:B0:C4:89 ROOT\SUN_VBOXNETFLTMP\0000
[00000013] VirtualBox Host-Only Ethernet Adapter 0 08:00:27:00:C4:A1 ROOT\NET\0000
[00000014] Microsoft ISATAP Adapter 0 ROOT\*ISATAP\0001
[00000015] VMware Virtual Ethernet Adapter for VMnet1 0 00:50:56:C0:00:01 ROOT\VMWARE\0000
[00000016] Microsoft ISATAP Adapter 0 ROOT\*ISATAP\0002
[00000017] VMware Virtual Ethernet Adapter for VMnet8 0 00:50:56:C0:00:08 ROOT\VMWARE\0001
[00000018] Microsoft ISATAP Adapter 0 ROOT\*ISATAP\0003
(Если я отключу свой физический адаптер, столбец MACAddress обнулится, а ConfigManagerErrorCode изменится на ненулевой).
К сожалению, этот класс просто слишком медленный. Любой запрос в Win32_NetworkAdapter последовательно занимает 0,3 секунды на моем относительно современном компьютере под управлением Windows 7 Core i7. Таким образом, использование этого добавит еще 0,3 секунды к запуску приложения (или хуже), что я считаю недопустимым. Это связано с тем, что я не могу придумать единственной уважительной причины, по которой выясняется, какие MAC-адреса и идентификаторы устройств plug-and-play находятся на локальном компьютере.
Поиск других методов для получения MAC-адреса дал функции GetAdaptersInfo и более новые GetAdaptersAddresses функции. У них нет 0,3-секундного штрафа, налагаемого WMI. Эти функции используются классом *. 1030 * NetworkInterface .NET Framework (как определено при изучении исходного кода .NET) и инструментом командной строки "ipconfig" (как определено с помощью Dependency Walker ).
Я сделал простой пример на C #, который перечисляет все сетевые адаптеры, используя класс NetworkInterface. К сожалению, использование этих API имеет два недостатка:
- Эти API даже не перечисляют отключенные сетевые адаптеры для начала. Это означает, что я не могу найти MAC-адрес для отключенного адаптера из моего кэша.
- Я не понимаю, как мне получить PNPDeviceID для фильтрации нефизических адаптеров.
Мой вопрос: каким способом я могу получить MAC-адрес физических адаптеров локального компьютера (включен он или нет) в течение нескольких десятков миллисекунд максимум?
(у меня есть опыт работы как на C #, так и на C ++, и я хорошо читаю на других языках, поэтому мне все равно, какой язык может использоваться в ответах).
РЕДАКТИРОВАТЬ: В ответ на предложение Алекса К использовать только немедленный возврат и пересылку, а также предоставить пример кода WMI для того, что я делаю, - вот код C #, в котором перечислены интересующие столбцы :
public static void NetTest() {
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
EnumerationOptions opt = new EnumerationOptions();
// WMI flag suggestions from Alex K:
opt.ReturnImmediately = true;
opt.Rewindable = false;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\cimv2", "select MACAddress, PNPDeviceID, ConfigManagerErrorCode from Win32_NetworkAdapter", opt);
foreach (ManagementObject obj in searcher.Get()) {
Console.WriteLine("=========================================");
foreach (PropertyData pd in obj.Properties) {
Console.WriteLine("{0} = {1}", pd.Name, pd.Value);
}
}
Console.WriteLine(sw.Elapsed.TotalSeconds);
}
Я вызывал эту функцию 3 раза, и каждый раз в последней строке печаталось около 0,36 секунды.Таким образом, предложенные флаги, кажется, не имеют никакого эффекта: положительный или отрицательный.Это не так уж и удивительно, поскольку ответ на Как сделать WMI-запросы только для чтения и только для чтения в C #? , кажется, указывает на то, что никаких изменений в производительности не будет наблюдаться, если не будет большого количества записей(например, от сотен до тысяч), что не относится к таблице Win32_NetworkAdapter.
РЕДАКТИРОВАТЬ 2: Было предложено несколько ответов для использования SendARP из API-помощника IP(это тот же API, который имеет функцию GetAdaptersInfo).Какие преимущества это дает по сравнению с GetAdaptersInfo для поиска локального MAC-адреса?Я не могу думать ни о чем - на первый взгляд, GetAdaptersInfo, похоже, возвращает более полный набор информации, чем SendARP для локальных адаптеров.Теперь, когда я думаю об этом, я думаю, что большая часть моего вопроса сосредоточена на концепции перечисления: какие адаптеры существуют на компьютере в первую очередь?SendARP не выполняет перечисление: предполагается, что вы уже знаете IP-адрес адаптера, для которого вы хотите MAC.Мне нужно выяснить, какие адаптеры существуют в системе.Возникают некоторые проблемы:
- Что произойдет, если сетевой кабель отключен?Например, это очень часто встречается на ноутбуке (отключенный Ethernet, отключенная карта WiFi).Я попытался использовать NetworkInterface.GetAllNetworkInterfaces () и перечислить все одноадресные адреса, используя GetIPProperties (). UnicastAddresses , когда носитель отключен.Windows не указывает ни одного адреса, поэтому я не могу вспомнить ни одного адреса, который можно было бы передать SendARP.Интуитивно понятно, что у отключенного адаптера все равно будет физический адрес, но нет IP-адреса (поскольку он не находится в сети с сервером DHCP).
- Что подводит меня к следующему: как получитьсписок локальных IP-адресов для проверки с помощью SendARP?
- Как получить PNPDeviceID (или аналогичный идентификатор, который можно использовать для фильтрации нефизических адаптеров) для каждого адаптера?
- Как мнеВывести список отключенных адаптеров, чтобы я мог найти MAC-адрес из своего кэша (т. е. MAC-адрес, который я нашел, когда он последний раз включался)?
Эти проблемы, похоже, не решаются с помощью SendARP,и являются основной причиной, по которой я задал этот вопрос (в противном случае я бы использовал GetAdaptersInfo и продолжал с вещами ...).