一台机器上可能不只有一个网卡,但每一个网卡只有一个MAC地址,而每一个网卡可能配置有多个IP地址;如平常的笔记本电脑中,就会有无线网卡和有线网卡(网线接口)两种;因此,如果要获得本机所有网卡的IP和MAC地址信息,则必须顺序获得每个网卡,再依次获取其信息等;在windows sdk中,用IP_ADAPTER_INFO结构体存储网卡信息,包括网卡名、网卡描述、网卡MAC地址、网卡IP等,该结构体的主要描述如下所示:
typedef struct _IP_ADAPTER_INFO {
struct _IP_ADAPTER_INFO* Next;//指向链表中下一个适配器信息的指针
DWORD ComboIndex;//预留值
char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];//使用ANSI字符串表示的适配器名称
char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];//使用ANSI字符串表示的适配器描述
UINT AddressLength;//适配器硬件地址以字节计算的长度
BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];//硬件地址以BYTE数组所表示
DWORD Index;//适配器索引
UINT Type;//适配器类型,主要有以下几种:
/*
* MIB_IF_TYPE_OTHER 1
* MIB_IF_TYPE_ETHERNET 6
* MIB_IF_TYPE_TOKENRING 9
* MIB_IF_TYPE_FDDI 15
* MIB_IF_TYPE_PPP 23
* MIB_IF_TYPE_LOOPBACK 24
* MIB_IF_TYPE_SLIP 28
*/
UINT DhcpEnabled;//指定这个适配器是否开启DHCP
PIP_ADDR_STRING CurrentIpAddress;//预留值
IP_ADDR_STRING IpAddressList;//该适配器的IPv4地址链表
IP_ADDR_STRING GatewayList;//该适配器的网关IPv4地址链表
IP_ADDR_STRING DhcpServer;//该适配器的DHCP服务器的IPv4 地址链表
BOOL HaveWins;
IP_ADDR_STRING PrimaryWinsServer;
IP_ADDR_STRING SecondaryWinsServer;
time_t LeaseObtained;
time_t LeaseExpires;
} IP_ADAPTER_INFO,*PIP_ADAPTER_INFO;
由于可能有多个网卡,因此struct _IP_ADAPTER_INFO* Next字段为一个链表结构指针,由于一个网卡可能有多个IP,因此IP_ADDR_STRING字段应该也是一个链表结构,其信息如下所示:
typedef struct _IP_ADDR_STRING
{
struct _IP_ADDR_STRING* Next; //指向同类型节点,即下一个IP(如果有多IP的话)
IP_ADDRESS_STRING IpAddress; //IP地址信息
IP_MASK_STRING IpMask; //IP子网掩码
DWORD Context;// 网络表入口。这个值对应着AddIPAddredd和DeleteIPAddress函数中的NTEContext参数
} IP_ADDR_STRING;
在基本了解以上信息后,就可以调用GetAdaptersInfo函数来获取相关网卡信息了,其通用的代码如下所示:
ahk 兼容A32 U32 U64
;转自 https://www.autohotkey.com/boards/viewtopic.php?f=9&t=18768&p=91413&hilit=GetAdaptersInfo#p91413
OutPut := GetAdaptersInfo()
PrintArr(OutPut)
GetAdaptersInfo()
{
; initial call to GetAdaptersInfo to get the necessary size
if (DllCall("iphlpapi.dll\GetAdaptersInfo", "ptr", 0, "UIntP", size) = 111) ; ERROR_BUFFER_OVERFLOW
if !(VarSetCapacity(buf, size, 0)) ; size ==> 1x = 704 | 2x = 1408 | 3x = 2112
return "Memory allocation failed for IP_ADAPTER_INFO struct"
; second call to GetAdapters Addresses to get the actual data we want
if (DllCall("iphlpapi.dll\GetAdaptersInfo", "ptr", &buf, "UIntP", size) != 0) ; NO_ERROR / ERROR_SUCCESS
return "Call to GetAdaptersInfo failed with error: " A_LastError
; get some information from the data we received
addr := &buf, IP_ADAPTER_INFO := {}
while (addr)
{
IP_ADAPTER_INFO[A_Index, "ComboIndex"] := NumGet(addr+0, o := A_PtrSize, "UInt") , o += 4
IP_ADAPTER_INFO[A_Index, "AdapterName"] := StrGet(addr+0 + o, 260, "CP0") , o += 260
IP_ADAPTER_INFO[A_Index, "Description"] := StrGet(addr+0 + o, 132, "CP0") , o += 132
IP_ADAPTER_INFO[A_Index, "AddressLength"] := NumGet(addr+0, o, "UInt") , o += 4
loop % IP_ADAPTER_INFO[A_Index].AddressLength
mac .= Format("{:02X}", NumGet(addr+0, o + A_Index - 1, "UChar")) "-"
IP_ADAPTER_INFO[A_Index, "Address"] := SubStr(mac, 1, -1), mac := "" , o += 8
IP_ADAPTER_INFO[A_Index, "Index"] := NumGet(addr+0, o, "UInt") , o += 4
IP_ADAPTER_INFO[A_Index, "Type"] := NumGet(addr+0, o, "UInt") , o += 4
IP_ADAPTER_INFO[A_Index, "DhcpEnabled"] := NumGet(addr+0, o, "UInt") , o += A_PtrSize
Ptr := NumGet(addr+0, o, "UPtr") , o += A_PtrSize
IP_ADAPTER_INFO[A_Index, "CurrentIpAddress"] := Ptr ? StrGet(Ptr + A_PtrSize, "CP0") : ""
IP_ADAPTER_INFO[A_Index, "IpAddressList"] := StrGet(addr + o + A_PtrSize, "CP0")
;~ IP_ADAPTER_INFO[A_Index, "IpMaskList"] := StrGet(addr + o + A_PtrSize + 16, "CP0") , o += A_PtrSize + 32 + A_PtrSize
IP_ADAPTER_INFO[A_Index, "IpMaskList"] := StrGet(addr + o + A_PtrSize * 3, "CP0") , o += A_PtrSize + 32 + A_PtrSize
IP_ADAPTER_INFO[A_Index, "GatewayList"] := StrGet(addr + o + A_PtrSize, "CP0") , o += A_PtrSize + 32 + A_PtrSize
IP_ADAPTER_INFO[A_Index, "DhcpServer"] := StrGet(addr + o + A_PtrSize, "CP0") , o += A_PtrSize + 32 + A_PtrSize
IP_ADAPTER_INFO[A_Index, "HaveWins"] := NumGet(addr+0, o, "Int") , o += A_PtrSize
IP_ADAPTER_INFO[A_Index, "PrimaryWinsServer"] := StrGet(addr + o + A_PtrSize, "CP0") , o += A_PtrSize + 32 + A_PtrSize
IP_ADAPTER_INFO[A_Index, "SecondaryWinsServer"] := StrGet(addr + o + A_PtrSize, "CP0") , o += A_PtrSize + 32 + A_PtrSize
IP_ADAPTER_INFO[A_Index, "LeaseObtained"] := DateAdd(NumGet(addr+0, o, "Int")) , o += A_PtrSize
IP_ADAPTER_INFO[A_Index, "LeaseExpires"] := DateAdd(NumGet(addr+0, o, "Int"))
addr := NumGet(addr+0, "UPtr")
}
; output the data we received and free the buffer
return IP_ADAPTER_INFO, VarSetCapacity(buf, 0), VarSetCapacity(addr, 0)
}
DateAdd(time)
{
if (time = 0)
return 0
datetime := 19700101
datetime += time, s
FormatTime, OutputVar, datetime, yyyy-MM-dd HH:mm:ss
return OutputVar
}
PrintArr(Arr, Option := "w800 h200", GuiNum := 90)
{
for index, obj in Arr {
if (A_Index = 1) {
for k, v in obj {
Columns .= k "|"
cnt++
}
Gui, %GuiNum%: Margin, 5, 5
Gui, %GuiNum%: Add, ListView, %Option%, % Columns
}
RowNum := A_Index
Gui, %GuiNum%: default
LV_Add("")
for k, v in obj {
LV_GetText(Header, 0, A_Index)
if (k <> Header) {
FoundHeader := False
loop % LV_GetCount("Column") {
LV_GetText(Header, 0, A_Index)
if (k <> Header)
continue
else {
FoundHeader := A_Index
break
}
}
if !(FoundHeader) {
LV_InsertCol(cnt + 1, "", k)
cnt++
ColNum := "Col" cnt
} else
ColNum := "Col" FoundHeader
} else
ColNum := "Col" A_Index
LV_Modify(RowNum, ColNum, (IsObject(v) ? "Object()" : v))
}
}
loop % LV_GetCount("Column")
LV_ModifyCol(A_Index, "AutoHdr")
Gui, %GuiNum%: Show,, Array
}
au3
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 634, 246)
$ListView1 = GUICtrlCreateListView("网卡名称|MAC地址|IP地址|链路速度", 8, 40, 618, 198)
_GUICtrlListView_SetColumnWidth($ListView1, 0, 290)
$Button1 = GUICtrlCreateButton("Exit", 552, 8, 75, 25)
GUISetState(@SW_SHOW)
#endregion ### END Koda GUI section ###
SetListView()
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE, $Button1
Exit
EndSwitch
WEnd
Func SetListView()
$a = _GetAdaptersInfo()
$index = ($a[1][3])
For $i = 1 To $a[0][0]
GUICtrlCreateListViewItem($a[$i][1] & '|' & _
StringLeft(Hex($a[$i][2]), 12) & '|' & _
$a[$i][6] & '|' & _
GetIfEntry($a[$i][3]) & ' MB', $ListView1)
Next
EndFunc ;==>SetListView
Func GetIfEntry($ifIndex)
Local $tagBuffer, $tBuffer, $pBuffer, $iResult, $iSpeed, $sDescr
$tagBuffer = "wchar[256];dword[5];byte[8];dword[16];char[256]"
$tBuffer = DllStructCreate($tagBuffer)
$pBuffer = DllStructGetPtr($tBuffer)
DllStructSetData($tBuffer, 2, $ifIndex, 1)
$iResult = DllCall("iphlpapi.dll", "long", "GetIfEntry", "ptr", $pBuffer)
$iSpeed = DllStructGetData($tBuffer, 2, 4) / 1000 / 1000
$sDescr = DllStructGetData($tBuffer, 5)
$tBuffer = 0
Return SetError($iResult[0], $iSpeed, $iSpeed)
EndFunc ;==>GetIfEntry
Func _GetAdaptersInfo()
Local $iResult, $tBuffer, $pBuffer, $aResult[1][9], $tagADPTINFO, $tAdpt
; 第一次调用传递空值,pOutBufLen ( $iResult[2] ) 设为结构所需大小,单位byte。
$iResult = DllCall("iphlpapi.dll", "dword", "GetAdaptersInfo", "ptr", 0, "ulong*", 0)
$tBuffer = DllStructCreate("byte[" & $iResult[2] & "]") ; 定义$iResult[2] 字节的缓存区域 (分配内存空间)。
$pBuffer = DllStructGetPtr($tBuffer) ; 获取内存指针。
; 第二次调用,GetAdaptersInfo把网卡信息复制到指定的内存空间 ($tBuffer) 中。
$iResult = DllCall("iphlpapi.dll", "dword", "GetAdaptersInfo", "ptr", $pBuffer, "ulong*", $iResult[2])
; $iResult[0]值为0则调用成功,否则为系统错误号。
; 数据转换, byte --> IP_ADAPTER_INFO
$tagADPTINFO = "ptr NextAdpt; dword ComboIndex; char AdptName[260]; char AdptDescr[132];uint AddrLength;byte MacAddr[8];dword Index;uint Type; uint DhcpEnabled;ptr CurrentIpAddr;ptr NextIpAddr; char IpAddr[16];char IpAddrMask[16]; dword IpAddrCxt; ptr NextGateway; char GatewayAddr[16]; char GatewayAddrMask[16];dword GatewayCxt; ptr NextDhcp; char DhcpAddr[16]; char DhcpAddrMask[16];dword DhcpCxt; int HaveWins; ptr NextPriWinsServer; char PriWinsServerAddr[16]; char PriWinsServerAddrMask[16]; dword PriWinsServerCxt; ptr NextSecWinsServer; char SecWinsServerAddr[16]; char SecWinsServerAddrMask[16]; dword LeaseObtained; dword LeaseExpires"
While $pBuffer
$tAdpt = DllStructCreate($tagADPTINFO, $pBuffer)
$aResult[0][0] += 1
ReDim $aResult[$aResult[0][0] + 1][9]
$aResult[$aResult[0][0]][0] = DllStructGetData($tAdpt, "AdptName") ; 网卡名称
$aResult[$aResult[0][0]][1] = DllStructGetData($tAdpt, "AdptDescr") ; 网卡描述
$aResult[$aResult[0][0]][2] = DllStructGetData($tAdpt, "MacAddr") ; 网卡MAC
$aResult[$aResult[0][0]][3] = DllStructGetData($tAdpt, "Index") ; 网卡索引号
$aResult[$aResult[0][0]][4] = DllStructGetData($tAdpt, "Type") ; 类型
$aResult[$aResult[0][0]][5] = DllStructGetData($tAdpt, "DhcpEnabled") ; DHCP是否启用 true = 启用, false = 禁用
$aResult[$aResult[0][0]][6] = DllStructGetData($tAdpt, "IpAddr") ; IP 地址
$aResult[$aResult[0][0]][7] = DllStructGetData($tAdpt, "GatewayAddr") ; 网关地址
$aResult[$aResult[0][0]][8] = DllStructGetData($tAdpt, "DhcpAddr") ; DHCP地址, 只有DhcpEnabled为true时,此值才有效。
$pBuffer = DllStructGetData($tAdpt, "NextAdpt") ; [下一张网卡信息的内存地址。]
$tAdpt = 0
WEnd
$tBuffer = 0
Return SetError($iResult[0], 0, $aResult)
EndFunc ;==>_GetAdaptersInfo