Jam*_*ton 4 c# c++ windows wmi networking
TL; DR版本的问题:WMI Win32_NetworkAdapter类包含我需要的信息,但是太慢了。在Windows上获取MACAddress,ConfigManagerErrorCode和PNPDeviceID列的信息的更快方法是什么?
我需要检索连接的网络适配器的信息,以便可以获取MAC地址来唯一标识本地Microsoft Windows计算机。WMI Win32_NetworkAdapter类似乎具有我在寻找的信息。MACAddress,ConfigManagerErrorCode和PNPDeviceID列是我真正需要的唯一列:
我的计划是使用PNPDeviceID过滤掉非物理设备。然后,我将在所有剩余的表条目上使用MACAddress列(将地址保存到缓存中)。当设备被禁用(可能由非零的ConfigManagerErrorCode指示)并且MACAddress为空时,我可以从缓存中对该设备使用以前看到的MACAddress。
您可以在Windows 7计算机上看到此表的内容。您可以看到其中有大量垃圾,但是只有一个带有“ PCI” PNPDeviceID的条目。
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
Run Code Online (Sandbox Code Playgroud)
(如果禁用物理适配器,则MACAddress列将变为null,并且ConfigManagerErrorCode更改为非零)。
不幸的是,这堂课太慢了。在我相对较新的基于Windows 7 Core i7的计算机上,Win32_NetworkAdapter上的任何查询始终需要0.3秒。因此,使用此方法将使应用程序启动又增加0.3秒(或更糟的时间),我认为这是不可接受的。尤其是因为我想不出一个唯一的正当理由,即弄清楚本地计算机上的MAC地址和即插即用设备ID需要花这么长时间。
搜索其他方法以获取MAC地址产生了GetAdaptersInfo和较新的GetAdaptersAddresses函数。他们没有WMI施加的0.3秒惩罚。这些功能是.NET Framework的NetworkInterface类(通过检查.NET源代码确定)和“ ipconfig”命令行工具(通过使用Dependency Walker确定)所使用的功能。
我在C#中做了一个简单的示例,其中列出了使用NetworkInterface类的所有网络适配器。不幸的是,使用这些API似乎有两个缺点:
我的问题是:最多可以在几十毫秒内使用什么方法来获取本地计算机的物理适配器的MAC地址(无论是否启用)?
(我在C#和C ++上都有丰富的经验,并且可以阅读其他语言,所以我真的不在乎答案中可能使用哪种语言)。
编辑: 作为对Alex K关于仅使用立即返回和正向返回的建议的回应,并且还为我在做什么提供了一些示例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);
}
Run Code Online (Sandbox Code Playgroud)
我调用了此函数3次,每次都在最后一行打印了0.36秒。因此,建议的标志似乎没有任何作用:正或负。这并不奇怪,因为如何在C#中进行仅转发,只读WMI查询?似乎表明除非有大量记录(例如几百到几千条),否则不会观察到性能的变化,而Win32_NetworkAdapter表不是这种情况。
编辑2: 已提出多个答案,以使用IP帮助程序API中的SendARP(这是具有GetAdaptersInfo函数的相同API)。与GetAdaptersInfo相比,这对于查找本地MAC地址有什么优势?我想不出什么-从表面上看,GetAdaptersInfo返回的信息集比SendARP对本地适配器的返回的信息更为详尽。现在,我考虑了一下,我认为我的问题很大一部分集中在枚举的概念上:计算机上首先存在哪些适配器?SendARP不执行枚举:它假定您已经知道想要MAC的适配器的IP地址。我需要弄清楚系统上存在哪些适配器。这引起了一些问题:
这些问题似乎无法由SendARP解决,这是我提出此问题的主要原因(否则,我将使用GetAdaptersInfo并继续进行操作...)。
我彻底放弃了WMI,在获得所需信息的同时进行了重大改进。正如WMI所指出的,要花费大于0.30秒才能获得结果。使用我的版本,我可以在约0.01秒内获得相同的信息。
我使用了设置API,配置管理器API,然后直接在NDIS网络驱动程序上发出OID请求以获取MAC地址。设置API似乎很慢,特别是在获取诸如属性值之类的东西时。必须将安装程序API调用降到最低。(通过查看在设备管理器中加载设备的“详细信息”选项卡需要多长时间,您实际上可以看到它有多严重)。
关于WMI为什么这么慢的猜测:我注意到WMI的Win32_NetworkAdapter总是花费相同的时间,无论我查询的是哪个属性子集。似乎WMI Win32_NetworkAdapter类的程序员很懒,并且没有像其他WMI类那样优化其类以仅收集所请求的信息。他们可能会收集所有信息,无论是否要求。他们可能极大地依赖Setup API来执行此操作,而对慢速Setup API的过多调用以获取不需要的信息是使它如此缓慢的原因。
我所做工作的高级概述:
结果是可以可靠地指示PC上的MAC地址,这些地址应不受VMware,VirtualBox制造的“假”网卡的影响,而不受临时禁用的网卡的影响,并不受通过USB,ExpressCard, PC卡或任何将来的可移动接口。
编辑: 并非所有网卡都支持IOCTL_NDIS_QUERY_GLOBAL_STATS。绝大多数都可以工作,但是有些英特尔卡却不能。请参阅如何根据给定的设备实例ID快速可靠地获取网卡的MAC地址。
| 归档时间: |
|
| 查看次数: |
8761 次 |
| 最近记录: |