GetAdaptersAddresses 对于 Vista 后的系统,获取网卡信息用 GetAdaptersAddresses 函数就够了,支持查询所有网卡、支持IPv6等。 但是对于 XP 系统,GetAdaptersAddresses
得到的结构体会少了些东西,在 XP 上IP_ADAPTER_ADDRESSES
被映射到IP_ADAPTER_ADDRESSES_XP
:
1 2 3 4 5 6 7 #if (NTDDI_VERSION >= NTDDI_VISTA) typedef IP_ADAPTER_ADDRESSES_LH IP_ADAPTER_ADDRESSES;typedef IP_ADAPTER_ADDRESSES_LH *PIP_ADAPTER_ADDRESSES;#elif (NTDDI_VERSION >= NTDDI_WINXP) typedef IP_ADAPTER_ADDRESSES_XP IP_ADAPTER_ADDRESSES;typedef IP_ADAPTER_ADDRESSES_XP *PIP_ADAPTER_ADDRESSES;#else
看看两者的差别:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 typedef struct _IP_ADAPTER_ADDRESSES_XP { union { ULONGLONG Alignment; struct { ULONG Length; DWORD IfIndex; }; }; struct _IP_ADAPTER_ADDRESSES_XP *Next; PCHAR AdapterName; PIP_ADAPTER_UNICAST_ADDRESS_XP FirstUnicastAddress; PIP_ADAPTER_ANYCAST_ADDRESS_XP FirstAnycastAddress; PIP_ADAPTER_MULTICAST_ADDRESS_XP FirstMulticastAddress; PIP_ADAPTER_DNS_SERVER_ADDRESS_XP FirstDnsServerAddress; PWCHAR DnsSuffix; PWCHAR Description; PWCHAR FriendlyName; BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; DWORD PhysicalAddressLength; DWORD Flags; DWORD Mtu; DWORD IfType; IF_OPER_STATUS OperStatus; DWORD Ipv6IfIndex; DWORD ZoneIndices[16 ]; PIP_ADAPTER_PREFIX_XP FirstPrefix; } IP_ADAPTER_ADDRESSES_XP, *PIP_ADAPTER_ADDRESSES_XP; typedef struct _IP_ADAPTER_ADDRESSES_LH { union { ULONGLONG Alignment; struct { ULONG Length; IF_INDEX IfIndex; }; }; struct _IP_ADAPTER_ADDRESSES_LH *Next; PCHAR AdapterName; PIP_ADAPTER_UNICAST_ADDRESS_LH FirstUnicastAddress; PIP_ADAPTER_ANYCAST_ADDRESS_XP FirstAnycastAddress; PIP_ADAPTER_MULTICAST_ADDRESS_XP FirstMulticastAddress; PIP_ADAPTER_DNS_SERVER_ADDRESS_XP FirstDnsServerAddress; PWCHAR DnsSuffix; PWCHAR Description; PWCHAR FriendlyName; BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; ULONG PhysicalAddressLength; union { ULONG Flags; struct { ULONG DdnsEnabled : 1 ; ULONG RegisterAdapterSuffix : 1 ; ULONG Dhcpv4Enabled : 1 ; ULONG ReceiveOnly : 1 ; ULONG NoMulticast : 1 ; ULONG Ipv6OtherStatefulConfig : 1 ; ULONG NetbiosOverTcpipEnabled : 1 ; ULONG Ipv4Enabled : 1 ; ULONG Ipv6Enabled : 1 ; ULONG Ipv6ManagedAddressConfigurationSupported : 1 ; }; }; ULONG Mtu; IFTYPE IfType; IF_OPER_STATUS OperStatus; IF_INDEX Ipv6IfIndex; ULONG ZoneIndices[16 ]; PIP_ADAPTER_PREFIX_XP FirstPrefix; ULONG64 TransmitLinkSpeed; ULONG64 ReceiveLinkSpeed; PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; PIP_ADAPTER_GATEWAY_ADDRESS_LH FirstGatewayAddress; ULONG Ipv4Metric; ULONG Ipv6Metric; IF_LUID Luid; SOCKET_ADDRESS Dhcpv4Server; NET_IF_COMPARTMENT_ID CompartmentId; NET_IF_NETWORK_GUID NetworkGuid; NET_IF_CONNECTION_TYPE ConnectionType; TUNNEL_TYPE TunnelType; SOCKET_ADDRESS Dhcpv6Server; BYTE Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; ULONG Dhcpv6ClientDuidLength; ULONG Dhcpv6Iaid; #if (NTDDI_VERSION >= NTDDI_VISTASP1) PIP_ADAPTER_DNS_SUFFIX FirstDnsSuffix; #endif } IP_ADAPTER_ADDRESSES_LH, *PIP_ADAPTER_ADDRESSES_LH;
其中子网掩码在FirstUnicastAddress
字段,这个字段在 XP 上也映射到了不同结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { union { ULONGLONG Alignment; struct { ULONG Length; DWORD Flags; }; }; struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next; SOCKET_ADDRESS Address; IP_PREFIX_ORIGIN PrefixOrigin; IP_SUFFIX_ORIGIN SuffixOrigin; IP_DAD_STATE DadState; ULONG ValidLifetime; ULONG PreferredLifetime; ULONG LeaseLifetime; UINT8 OnLinkPrefixLength; } IP_ADAPTER_UNICAST_ADDRESS_LH, typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { union { ULONGLONG Alignment; struct { ULONG Length; DWORD Flags; }; }; struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next; SOCKET_ADDRESS Address; IP_PREFIX_ORIGIN PrefixOrigin; IP_SUFFIX_ORIGIN SuffixOrigin; IP_DAD_STATE DadState; ULONG ValidLifetime; ULONG PreferredLifetime; ULONG LeaseLifetime; } IP_ADAPTER_UNICAST_ADDRESS_XP, *PIP_ADAPTER_UNICAST_ADDRESS_XP;
其中OnLinkPrefixLength
就是网卡的子网掩码,但是 XP 系统上没有这个字段,不过还有其他补救方法。
GetAdaptersInfo GetAdaptersInfo 用于获取所有活动网卡信息。 它可以获取网卡的IP地址、子网掩码、MAC地址信息,其中IP地址和子网掩码以字符串形式返回,如果想要int
类型的话需要自行处理。 一个要求 Vista+ 的转换实现:
1 2 3 4 5 SOCKADDR_IN addr; INT addrLen = sizeof (SOCKADDR_IN); WSAStringToAddressA (p->IpAddressList.IpAddress.String, AF_INET, NULL , (LPSOCKADDR)&addr, &addrLen);unsigned long ipInt = addr.sin_addr.s_addr; ipInt = ntohl (ipInt);
更简单的版本:
1 2 3 4 5 unsigned ip_str_to_u32 (const char * ip) { unsigned a, b, c, d; sscanf (ip, "%u.%u.%u.%u" , &a, &b, &c, &d); return (a << 24 ) | (b << 16 ) | (c << 8 ) | d; }
GetIpAddrTable GetIpAddrTable 可以获取系统上的 IP 地址表,会得到一个 MIB_IPADDRROW_XP 结构列表,其中dwMask
字段就是当前 IP 地址的掩码,但是并不知道 IP 属于哪个网卡,此时有两种选择:
再次调用 GetIfEntry 函数得到其网卡信息(其中还有MAC地址)。
先用GetAdaptersAddresses
获取网卡列表,再用GetIpAddrTable
获取 IP 地址表,然后比较两者的 IP 地址或dwIndex
字段。
这要调用两个函数,不推荐。
其他相关函数
总结 要在 XP 系统上枚举网卡并得到IP、子网掩码、MAC地址信息的话用 GetAdaptersInfo 就够了。 不需要支持 XP 系统的话用更新的 GetAdaptersAddresses 函数。
相关阅读 list adapters addresses and mask/prefix, both IPv4 and IPv6 (GetAdaptersAddresses)