C# 用于获取本地计算机MAC地址的Win32_NetworkAdapter WMI类的快速替换
TL;此问题的DR版本:WMI类包含我需要的信息,但速度太慢。在Windows上获取MACAddress、ConfigManagerErrorCode和PNPDeviceID列信息的更快方法是什么 我需要检索连接的网络适配器的信息,以便获得唯一标识本地Microsoft Windows计算机的MAC地址。WMI类似乎具有我要查找的信息。MACAddress、ConfigManagerErrorCode和PNPDeviceID列是我真正需要的唯一列:C# 用于获取本地计算机MAC地址的Win32_NetworkAdapter WMI类的快速替换,c#,c++,windows,networking,wmi,C#,C++,Windows,Networking,Wmi,TL;此问题的DR版本:WMI类包含我需要的信息,但速度太慢。在Windows上获取MACAddress、ConfigManagerErrorCode和PNPDeviceID列信息的更快方法是什么 我需要检索连接的网络适配器的信息,以便获得唯一标识本地Microsoft Windows计算机的MAC地址。WMI类似乎具有我要查找的信息。MACAddress、ConfigManagerErrorCode和PNPDeviceID列是我真正需要的唯一列: MACAddress:MAC地址(此操作的目
- MACAddress:MAC地址(此操作的目标)
- ConfigManagerErrorCode:允许我确定适配器是否已启用并正在运行。(如果它被禁用,那么我应该使用我的应用程序以前缓存的MAC地址(如果可用)
- PNPDeviceID:通过检查前缀“PCI”(如果需要,可能还有其他接口),我可以筛选出非物理适配器,其中有几个在我的Windows 7机箱上(包括虚拟适配器,如VMware/VirtualBox)
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列变为null,ConfigManagerErrorCode变为非零)
不幸的是,这个类太慢了。在我相对现代的基于Windows 7 Core i7的计算机上,对Win32_NetworkAdapter的任何查询始终需要0.3秒。因此,使用此选项将使应用程序启动时间再增加0.3秒(或更糟),这是我无法接受的。这尤其是因为我想不出一个合理的理由来解释为什么要花这么长时间才能弄清楚本地计算机上的MAC地址和即插即用设备ID
public static void ShowNetworkInterfaces()
{
IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
Console.WriteLine("Interface information for {0}.{1} ",
computerProperties.HostName, computerProperties.DomainName);
if (nics == null || nics.Length < 1)
{
Console.WriteLine(" No network interfaces found.");
return;
}
Console.WriteLine(" Number of interfaces .................... : {0}", nics.Length);
foreach (NetworkInterface adapter in nics)
{
IPInterfaceProperties properties = adapter.GetIPProperties(); // .GetIPInterfaceProperties();
Console.WriteLine();
Console.WriteLine(adapter.Description);
Console.WriteLine(String.Empty.PadLeft(adapter.Description.Length,'='));
Console.WriteLine(" Interface type .......................... : {0}", adapter.NetworkInterfaceType);
Console.Write(" Physical address ........................ : ");
PhysicalAddress address = adapter.GetPhysicalAddress();
byte[] bytes = address.GetAddressBytes();
for(int i = 0; i< bytes.Length; i++)
{
// Display the physical address in hexadecimal.
Console.Write("{0}", bytes[i].ToString("X2"));
// Insert a hyphen after each byte, unless we are at the end of the
// address.
if (i != bytes.Length -1)
{
Console.Write("-");
}
}
Console.WriteLine();
}
}
搜索获取MAC地址的其他方法产生了和更新的函数。他们没有WMI施加的0.3秒惩罚。这些函数是.NET Framework类(通过检查.NET源代码确定)和“ipconfig”命令行工具(通过使用确定)使用的函数
我用C#做了一个简单的例子,列出了使用NetworkInterface类的所有网络适配器。不幸的是,使用这些API似乎有两个缺点:
- 这些API甚至没有列出禁用的网络适配器。这意味着我无法从缓存中查找禁用适配器的MAC地址
- 我不知道如何让PNPDeviceID过滤掉非物理适配器
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秒。因此,建议的标志似乎没有任何效果:正面或负面。这并不奇怪,因为的答案似乎表明,除非有大量记录(例如数百到数千条),否则不会观察到性能的变化,而Win32_NetworkAdapter表则不是这样
编辑2:建议从IP helper API使用多个答案(这是具有GetAdapterInfo函数的同一个API)。与GetAdapterInfo相比,它在查找本地MAC地址方面有什么优势?我想不出任何信息——表面上看,GetAdapterInfo似乎比SendARP对本地适配器返回的信息更全面。现在回想起来,我认为我的问题的很大一部分集中在枚举的概念上:首先,计算机上存在哪些适配器?SendARP不执行枚举:它假定您已经知道您想要MAC的适配器的IP地址。我需要弄清楚系统上存在哪些适配器。这引发了一些问题:
- 如果拔下网络电缆,会发生什么情况?这在笔记本电脑上非常常见,例如(未连接的以太网、未连接的WiFi卡)。我尝试使用NetworkInterface.GetAllNetworkInterfaces()并列出媒体拔出时使用的所有单播地址。Windows没有列出地址,所以我想不出任何可以传递给SendARP的地址。直观地说,拔掉插头的适配器仍然有一个物理地址,但没有IP地址(因为它不在具有DHCP服务器的网络上)
- 这让我想到:我如何获得一个本地IP地址列表,用SendARP进行测试
- 如何获取每个适配器的PNPDeviceID(或可用于筛选非物理适配器的类似ID)
- 如何列出禁用的适配器,以便从缓存中查找MAC地址(即上次启用时找到的MAC地址)
SendARP似乎没有解决这些问题,这是我问这个问题的主要原因(否则我将使用GetAdapterInfo并继续处理…。您应该能够从
System.Net
命名空间获得所需的一切。例如,下面的语句和w