unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
rsilvestri
Posts: 4
Joined: 07 May 2018, 16:55

unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

07 May 2018, 17:15

Being a newbi with AutoHotKey deveopment, I am trying to extract the network configuration details out of iphlpapi.dll\GetAdaptersAddresses.

all needed information in IP_ADAPTER_ADDRESSES structure I manged reasonably. Just trying to get information which are exposed by Pointers I completely struggle.

Any hint or support is very much appreciated.

Code: Select all

#Persistent
#warn
OutPut := GetAdaptersAddresses()
PrintArr(OutPut)

GetAdaptersAddresses()
{
	vAdapterAddresses := A_PtrSize ? "Ptr" : "UInt"
	vSizePointer := A_PtrSize ? "Ptr" : "UInt"
	vSizePointer := 0
	
    ; initial call to GetAdaptersAddresses to get the necessary size
    vResult := DllCall("iphlpapi.dll\GetAdaptersAddresses", "Int", 0, "Int", 0, "UPTR", 0, "UPTR", &vAdapterAddresses, "UPTR", &vSizePointer)
	if ( vResult = 111) ; ERROR_BUFFER_OVERFLOW
	{
		;msgbox %vResult% . " / " . %vSizePointer%
		if !(VarSetCapacity(vAdapterAddresses, vSizePointer, 0))  ; vSizePointer ==>  1x = 704  |  2x = 1408  |  3x = 2112
			{
					msgbox "Memory allocation failed for IP_ADAPTER_INFO struct"
					return "Memory allocation failed for IP_ADAPTER_INFO struct"
			}
	}
	
	; second call to GetAdapters Addresses to get the actual data we want
    vResult := DllCall("iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "UPTR", 0, "UPTR", &vAdapterAddresses, "UPTR", &vSizePointer)
	if ( vResult != 0) ; NO_ERROR / ERROR_SUCCESS
	{
		msgbox "Call to GetAdaptersAddresses failed with error: " %vResult%
        return "Call to GetAdaptersAddresses failed with error: " vResult
	}

    ; get some information from the data we received
    addr := &vAdapterAddresses+0, IP_ADAPTER_ADDRESSES := {}

	y := &vSizePointer
	
	msgbox "addr = " %addr% " / length " %y%
	iaddr := addr
	
	while (addr)
    {
		IP_ADAPTER_ADDRESSES [A_Index, "addr"] 			   := addr
													   vLength := NumGet(addr+0, o := 0, "UINT")  , o += A_PtrSize  ; 0
		IP_ADAPTER_ADDRESSES [A_Index, "vLength"] 			   := vLength
		
													  vIfIndex := NumGet(addr+0, o , "UINT")  , o += A_PtrSize		; 4
		IP_ADAPTER_ADDRESSES [A_Index, "ifIndex"] 			   := vIfIndex

													     vNext := NumGet(addr+0, o , "UINT")  , o += A_PtrSize		; 8
;		IP_ADAPTER_ADDRESSES [A_Index, "Next"] 			   := vNext
		
												  pAdapterName := NumGet(addr+0, o, "UPTR"), o += A_PtrSize			; 12
												  vAdapterName := StrGet(pAdapterName, "CP0")
		IP_ADAPTER_ADDRESSES [A_Index, "AdapterName"]          := vAdapterName

										  pFirstUnicastAddress := NumGet(addr+0, o, "UPTR"), o += A_PtrSize			;16
										  vTest := 	NumGet(pFirstUnicastAddress, 12, "UINT")
		IP_ADAPTER_ADDRESSES [A_Index, "FirstUnicastAddress"]  := pFirstUnicastAddress
		
										  pFirstAnycastAddress := NumGet(addr+0, o, "UPTR")   , o += A_PtrSize		;20
		IP_ADAPTER_ADDRESSES [A_Index, "FirstAnycastAddress"]  := pFirstAnycastAddress

										pFirstMulticastAddress := NumGet(addr+0, o, "UPTR")   , o += A_PtrSize		;24
		IP_ADAPTER_ADDRESSES [A_Index, "FirstMulticastAddress"]:= pFirstMulticastAddress

		IP_ADAPTER_ADDRESSES [A_Index, "a_pos"]           	   := o
										pFirstDnsServerAddress := NumGet(addr+0, o, "UPTR")   , o += A_PtrSize		;28 
										
										
;											       lpsaAddress := NumGet(pFirstDnsServerAddress, 12, "PTR")         ;8 ;10.0.0.1
;											   dwAddressLength := NumGet(pFirstDnsServerAddress, 16, "INT")         ;8 ;10.0.0.1
;			vTest := DllCall("Ws2_32.lib\WSAAddressToString", "UPTR", lpsaAddress, "UPTR", dwAddressLength, "UPTR", 0, "UPTR", &lpszAddressString, "UPTR", &lpdwAddressStringLength)

												
		IP_ADAPTER_ADDRESSES [A_Index, "DnsTest"]              := vTest
		IP_ADAPTER_ADDRESSES [A_Index, "FirstDnsServerAddress"]:= pFirstDnsServerAddress
										
										
										
;		msgbox %A_Index% " / " %pFirstDnsServerAddress% ;" / " %vDnsLength%  " / " %t%
										

													pDnsSuffix := NumGet(addr+0, o, "UINT")   , o += A_PtrSize		;32
													vDnsSuffix := StrGet(pDnsSuffix)   
		IP_ADAPTER_ADDRESSES [A_Index, "DnsSuffix"]            := vDnsSuffix
		
												  pDescription := NumGet(addr+0, o, "UINT"), o += A_PtrSize 		;36
												  vDescription := StrGet(pDescription)
		IP_ADAPTER_ADDRESSES [A_Index, "Description"]          := vDescription

												 pFriendlyName := NumGet(addr+0, o, "UINT"), o += A_PtrSize 		;40
												 vFriendlyName := StrGet(pFriendlyName )  
		IP_ADAPTER_ADDRESSES [A_Index, "FriendlyName"]         := vFriendlyName

									    pPhysicalAddressLength := NumGet(addr+0, o + 8, "UCHAR")		 			;52
		IP_ADAPTER_ADDRESSES [A_Index, "PhysicalAddressLength"]:= pPhysicalAddressLength
	
		mac :=""
        loop % pPhysicalAddressLength
			mac .= Format("{:02X}", NumGet(addr+0, o + A_Index - 1, "UChar")) "-"
        IP_ADAPTER_ADDRESSES[A_Index, "Address"]               := SubStr(mac, 1, -1), mac := "", o += 12			;44

														pFlags := NumGet(addr+0, o, "UINT"), o += 4 				;56
		IP_ADAPTER_ADDRESSES [A_Index, "Flags"]                := pFlags

														  pMtu := NumGet(addr+0, o, "UINT"), o += 4 				;60
		IP_ADAPTER_ADDRESSES [A_Index, "Mtu"]                  := pMtu
		
													   pIfType := NumGet(addr+0, o, "UINT"), o += 4 				;64
		IP_ADAPTER_ADDRESSES [A_Index, "ifType"]               := pIfType
		
												 pIfOperStatus := NumGet(addr+0, o, "UINT"), o += 4 				;68
		IP_ADAPTER_ADDRESSES [A_Index, "ifOperStatus"]         := pIfOperStatus
		
		
		




		;msgbox "test : " . %addr%+0 
		
		addr := vNext
		
    }
	;msgbox "test : " . NumGet(addr+0, o := A_PtrSize, "UInt")
    ; output the data we received and free the buffer
    return IP_ADAPTER_ADDRESSES, VarSetCapacity(vAdapterAddresses, 0), VarSetCapacity(addr, 0)
}


PrintArr(Arr, Option := "w1200 h200", GuiNum := 90)
{
	cnt:=0
    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
}
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

10 May 2018, 22:15

This is an attempt, but not finished. I hate that structure :lol: .
Do you really need all the information?

Code: Select all

ERROR_SUCCESS := 0
ERROR_BUFFER_OVERFLOW := 111

; #1, get required size
SizePointer := 0
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", 0, "UIntP", SizePointer)
If (Ret != ERROR_BUFFER_OVERFLOW)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

; #2, retrieves the addresses associated with the adapters on the local computer
; IP_ADAPTER_ADDRESSES structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
VarSetCapacity(PIP_ADAPTER_ADDRESSES, SizePointer)
; GetAdaptersAddresses function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", &PIP_ADAPTER_ADDRESSES, "UIntP", SizePointer)
If (Ret != ERROR_SUCCESS)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

Ptr := &PIP_ADAPTER_ADDRESSES
Loop
{
    IP_ADAPTER_ADDRESSES := IP_ADAPTER_ADDRESSES(Ptr)
    MsgBox % "AdapterName: "    . IP_ADAPTER_ADDRESSES.AdapterName
           . "`nDescription: "  . IP_ADAPTER_ADDRESSES.Description
           . "`nFriendlyName: " . IP_ADAPTER_ADDRESSES.FriendlyName
    If (!(Ptr := IP_ADAPTER_ADDRESSES.Next))
        Break
}


; IP_ADAPTER_ADDRESSES structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
IP_ADAPTER_ADDRESSES(Ptr)
{
    Static MAX_ADAPTER_ADDRESS_LENGTH := 8

                  ; Reserved. Used by the compiler to align the structure
    Local Data := { Alignment: NumGet(Ptr+0, "UInt64")
                  ; The length, in bytes, of this structure
                  , Length: NumGet(Ptr+0, "UInt")
                  ; The index of the IPv4 interface with which these addresses are associated
                  , IfIndex: NumGet(Ptr + 4, "UInt")
                  ; A pointer to the next adapter addresses structure in the list
                  , Next: NumGet(Ptr + 8, "UPtr")
                  ; An array of characters that contains the name of the adapter with which these addresses are associated
                  , AdapterName: StrGet(NumGet(Ptr + 8 + A_PtrSize, "UPtr"), "UTF-8")
                  ; A pointer to the first IP_ADAPTER_UNICAST_ADDRESS structure in a linked list of IP unicast addresses for the adapter
                  , PIP_ADAPTER_UNICAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*2, "UPtr")
                  ; A pointer to the first IP_ADAPTER_ANYCAST_ADDRESS structure in a linked list of IP anycast addresses for the adapter
                  , PIP_ADAPTER_ANYCAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*3, "UPtr")
                  ; A pointer to the first IP_ADAPTER_MULTICAST_ADDRESS structure in a list of IP multicast addresses for the adapter
                  , PIP_ADAPTER_MULTICAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*4, "UPtr")
                  ; A pointer to the first IP_ADAPTER_DNS_SERVER_ADDRESS structure in a linked list of DNS server addresses for the adapter
                  , PIP_ADAPTER_DNS_SERVER_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*5, "UPtr")
                  ; The Domain Name System (DNS) suffix associated with this adapter
                  , DnsSuffix: StrGet(NumGet(Ptr + 8 + A_PtrSize*6, "UPtr"), "UTF-16")
                  ; A description for the adapter. This member is read-only
                  , Description: StrGet(NumGet(Ptr + 8 + A_PtrSize*7, "UPtr"), "UTF-16")
                  ; A user-friendly name for the adapter. For example: "Local Area Connection 1." This name appears in contexts such as the ipconfig command line program and the Connection folder
                  , FriendlyName: StrGet(NumGet(Ptr + 8 + A_PtrSize*8, "UPtr"), "UTF-16")
                  ; The Media Access Control (MAC) address for the adapter. For example, on an Ethernet network this member would specify the Ethernet hardware address
                  , PhysicalAddress: Ptr + 8 + A_PtrSize*9
                  ; The length, in bytes, of the address specified in the PhysicalAddress member
                  , PhysicalAddressLength: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH, "UInt")
                  ; A set of flags specifying various settings for the adapter
                  , Flags: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4, "UInt")
                  ; The maximum transmission unit (MTU) size, in bytes
                  , Mtu: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*2, "UInt")
                  ; The interface type as defined by the Internet Assigned Names Authority (IANA)
                  , IfType: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*3, "UInt")
                  ; The operational status for the interface as defined in RFC 2863
                  , OperStatus: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*4, "Int")
                  ; The interface index for the IPv6 IP address. This member is zero if IPv6 is not available on the interface
                  , Ipv6IfIndex: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*5, "Int")
                  ; An array of scope IDs for each scope level used for composing sockaddr structures. The SCOPE_LEVEL enumeration is used to index the array. On IPv6, a single interface may be assigned multiple IPv6 multicast addresses based on a scope ID
                  , ZoneIndices: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6    ; DWORD[16]
                  , FirstPrefix: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16, "UPtr")
                  ; The current speed in bits per second of the transmit link for the adapter
                  , TransmitLinkSpeed: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize, "UInt64")
                  , ReceiveLinkSpeed: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8, "UInt64")
                  , FirstWinsServerAddress: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2, "UPtr")
                  , FirstGatewayAddress: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize, "UPtr")
                  , Ipv4Metric: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2, "UInt") }
                  ;, Ipv6Metric: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4, "UInt")
                  ;, Luid: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4*2    ; sizeof IF_LUID = 8
                  ;, Dhcpv4Server: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4*2 + 8
                  ; ...

    Return Data
}
rsilvestri
Posts: 4
Joined: 07 May 2018, 16:55

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 05:06

thanks very much for this support. I fully agree to the frustration with this structure. The information I am searching for are the DNS Servers assigned to the interface which are exposed by a pointer only.

The one point I still am fighting with is on how to read such sub-structures as for PIP_ADAPTER_DNS_SERVER_ADDRESS. I tried to add a respective object and populate the structure similarly to your sample. Though I get an error returned "Return's parameter should be blank except inside a function.". What is missing here?

Code: Select all

ERROR_SUCCESS := 0
ERROR_BUFFER_OVERFLOW := 111

; #1, get required size
SizePointer := 0
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", 0, "UIntP", SizePointer)
If (Ret != ERROR_BUFFER_OVERFLOW)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

; #2, retrieves the addresses associated with the adapters on the local computer
; IP_ADAPTER_ADDRESSES structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
VarSetCapacity(PIP_ADAPTER_ADDRESSES, SizePointer)
; GetAdaptersAddresses function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", &PIP_ADAPTER_ADDRESSES, "UIntP", SizePointer)
If (Ret != ERROR_SUCCESS)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

Ptr := &PIP_ADAPTER_ADDRESSES
Loop
{
    IP_ADAPTER_ADDRESSES := IP_ADAPTER_ADDRESSES(Ptr)
	PIP_ADAPTER_UNICAST_ADDRESS := PIP_ADAPTER_UNICAST_ADDRESS(IP_ADAPTER_ADDRESSES.PIP_ADAPTER_DNS_SERVER_ADDRESS)
	
    MsgBox % "AdapterName   : " . IP_ADAPTER_ADDRESSES.AdapterName
           . "`nDescription : " . IP_ADAPTER_ADDRESSES.Description
           . "`nFriendlyName: " . IP_ADAPTER_ADDRESSES.FriendlyName
           . "`nDNS Server  : " . IP_ADAPTER_ADDRESSES.PIP_ADAPTER_DNS_SERVER_ADDRESS
		   . "`nLength      : " . IP_ADAPTER_ADDRESSES.Length
		   . "`nDNS Length  : " . PIP_ADAPTER_UNICAST_ADDRESS.Length
		   
		   
    If (!(Ptr := IP_ADAPTER_ADDRESSES.Next))
        Break
}


; IP_ADAPTER_ADDRESSES structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
IP_ADAPTER_ADDRESSES(Ptr)
{
    Static MAX_ADAPTER_ADDRESS_LENGTH := 8

                  ; Reserved. Used by the compiler to align the structure
    Local Data := { Alignment: NumGet(Ptr+0, "UInt64")
                  ; The length, in bytes, of this structure
                  , Length: NumGet(Ptr+0, "UInt")
                  ; The index of the IPv4 interface with which these addresses are associated
                  , IfIndex: NumGet(Ptr + 4, "UInt")
                  ; A pointer to the next adapter addresses structure in the list
                  , Next: NumGet(Ptr + 8, "UPtr")
                  ; An array of characters that contains the name of the adapter with which these addresses are associated
                  , AdapterName: StrGet(NumGet(Ptr + 8 + A_PtrSize, "UPtr"), "UTF-8")
                  ; A pointer to the first IP_ADAPTER_UNICAST_ADDRESS structure in a linked list of IP unicast addresses for the adapter
                  , PIP_ADAPTER_UNICAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*2, "UPtr")
                  ; A pointer to the first IP_ADAPTER_ANYCAST_ADDRESS structure in a linked list of IP anycast addresses for the adapter
                  , PIP_ADAPTER_ANYCAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*3, "UPtr")
                  ; A pointer to the first IP_ADAPTER_MULTICAST_ADDRESS structure in a list of IP multicast addresses for the adapter
                  , PIP_ADAPTER_MULTICAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*4, "UPtr")
                  ; A pointer to the first IP_ADAPTER_DNS_SERVER_ADDRESS structure in a linked list of DNS server addresses for the adapter
                  , PIP_ADAPTER_DNS_SERVER_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*5, "UPtr")
                  ; The Domain Name System (DNS) suffix associated with this adapter
                  , DnsSuffix: StrGet(NumGet(Ptr + 8 + A_PtrSize*6, "UPtr"), "UTF-16")
                  ; A description for the adapter. This member is read-only
                  , Description: StrGet(NumGet(Ptr + 8 + A_PtrSize*7, "UPtr"), "UTF-16")
                  ; A user-friendly name for the adapter. For example: "Local Area Connection 1." This name appears in contexts such as the ipconfig command line program and the Connection folder
                  , FriendlyName: StrGet(NumGet(Ptr + 8 + A_PtrSize*8, "UPtr"), "UTF-16")
                  ; The Media Access Control (MAC) address for the adapter. For example, on an Ethernet network this member would specify the Ethernet hardware address
                  , PhysicalAddress: Ptr + 8 + A_PtrSize*9
                  ; The length, in bytes, of the address specified in the PhysicalAddress member
                  , PhysicalAddressLength: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH, "UInt")
                  ; A set of flags specifying various settings for the adapter
                  , Flags: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4, "UInt")
                  ; The maximum transmission unit (MTU) size, in bytes
                  , Mtu: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*2, "UInt")
                  ; The interface type as defined by the Internet Assigned Names Authority (IANA)
                  , IfType: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*3, "UInt")
                  ; The operational status for the interface as defined in RFC 2863
                  , OperStatus: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*4, "Int")
                  ; The interface index for the IPv6 IP address. This member is zero if IPv6 is not available on the interface
                  , Ipv6IfIndex: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*5, "Int")
                  ; An array of scope IDs for each scope level used for composing sockaddr structures. The SCOPE_LEVEL enumeration is used to index the array. On IPv6, a single interface may be assigned multiple IPv6 multicast addresses based on a scope ID
                  , ZoneIndices: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6    ; DWORD[16]
                  , FirstPrefix: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16, "UPtr")
                  ; The current speed in bits per second of the transmit link for the adapter
                  , TransmitLinkSpeed: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize, "UInt64")
                  , ReceiveLinkSpeed: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8, "UInt64")
                  , FirstWinsServerAddress: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2, "UPtr")
                  , FirstGatewayAddress: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize, "UPtr")
                  , Ipv4Metric: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2, "UInt") }
                  ;, Ipv6Metric: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4, "UInt")
                  ;, Luid: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4*2    ; sizeof IF_LUID = 8
                  ;, Dhcpv4Server: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4*2 + 8
                  ; ...

    Return Data
}

PIP_ADAPTER_UNICAST_ADDRESS(Ptr)
{
                  ; Reserved. Used by the compiler to align the structure
    Local Data := { Alignment: NumGet(Ptr+0, "UInt64")
                  ; The length, in bytes, of this structure
                  , Length: NumGet(Ptr+0, "UInt")
				  }

    Return Data
				  
}
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 05:38

Code: Select all

PIP_ADAPTER_UNICAST_ADDRESS(Ptr)
{
                  ; Reserved. Used by the compiler to align the structure
    Local Data := { Alignment: NumGet(Ptr+0, "UInt64")
                  ; The length, in bytes, of this structure
                  , Length: NumGet(Ptr+0, "UInt")
				  } ; move this brace to the line above

    Return Data
				  
}
See comment, you can't do it like that in v1.

Cheers.
rsilvestri
Posts: 4
Joined: 07 May 2018, 16:55

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 09:10

Perfect, that helped well.

Now I am fighting to translate SOCKADDR into string values of addresses which should be possible by using "Ws2_32.dll\WSAAddressToString".

When calling though "Ws2_32.dll\WSAAddressToString" I get -1 return and don't get the reason:

Code: Select all

Ret := DllCall("Ws2_32.dll\WSAAddressToString", "Ptr", IP_ADAPTER_DNS_SERVER_ADDRESS.SAptr, "UInt", IP_ADAPTER_DNS_SERVER_ADDRESS.SAlength, "Ptr", 0, "Ptr", IPSTR, "UInt", IPSTRlength)
Full code:

Code: Select all

ERROR_SUCCESS := 0
ERROR_BUFFER_OVERFLOW := 111

; #1, get required size
SizePointer := 0
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", 0, "UIntP", SizePointer)
If (Ret != ERROR_BUFFER_OVERFLOW)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

; #2, retrieves the addresses associated with the adapters on the local computer
; IP_ADAPTER_ADDRESSES structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
VarSetCapacity(PIP_ADAPTER_ADDRESSES, SizePointer)
; GetAdaptersAddresses function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", &PIP_ADAPTER_ADDRESSES, "UIntP", SizePointer)
If (Ret != ERROR_SUCCESS)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

Ptr := &PIP_ADAPTER_ADDRESSES
Loop
{
    IP_ADAPTER_ADDRESSES := IP_ADAPTER_ADDRESSES(Ptr)
	IP_ADAPTER_DNS_SERVER_ADDRESS  := IP_ADAPTER_DNS_SERVER_ADDRESS(IP_ADAPTER_ADDRESSES.PIP_ADAPTER_DNS_SERVER_ADDRESS)
	SOCKADDR := SOCKADDR(IP_ADAPTER_DNS_SERVER_ADDRESS.SAptr)
	
	IPSTRlength := 1024
	Ret := DllCall("Ws2_32.dll\WSAAddressToString", "Ptr", IP_ADAPTER_DNS_SERVER_ADDRESS.SAptr, "UInt", IP_ADAPTER_DNS_SERVER_ADDRESS.SAlength, "Ptr", 0, "Ptr", IPSTR, "UInt", IPSTRlength)
	If (Ret != ERROR_SUCCESS)
	{
		MsgBox % "ERROR #" . Ret . " / IPSTRlength :" . IPSTRlength
		ExitApp
	}
	
	
	
    MsgBox % "AdapterName      : " . IP_ADAPTER_ADDRESSES.AdapterName
           . "`nDescription    : " . IP_ADAPTER_ADDRESSES.Description
           . "`nFriendlyName   : " . IP_ADAPTER_ADDRESSES.FriendlyName
           . "`nDNS Server     : " . IP_ADAPTER_ADDRESSES.PIP_ADAPTER_DNS_SERVER_ADDRESS
		   . "`nLength         : " . IP_ADAPTER_ADDRESSES.Length
		   . "`nDNS Length     : " . IP_ADAPTER_DNS_SERVER_ADDRESS.Length
		   . "`nDNS Server     : " . IP_ADAPTER_DNS_SERVER_ADDRESS.SAlength
		   . "`nSOCKADDR 1     : " . SOCKADDR.SAfamily
		   . "`nSOCKADDR 2     : " . SOCKADDR.sa_data
		   
		   
    If (!(Ptr := IP_ADAPTER_ADDRESSES.Next))
        Break
}


; IP_ADAPTER_ADDRESSES structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
IP_ADAPTER_ADDRESSES(Ptr)
{
    Static MAX_ADAPTER_ADDRESS_LENGTH := 8

                  ; Reserved. Used by the compiler to align the structure
    Local Data := { Alignment: NumGet(Ptr+0, "UInt64")
                  ; The length, in bytes, of this structure
                  , Length: NumGet(Ptr+0, "UInt")
                  ; The index of the IPv4 interface with which these addresses are associated
                  , IfIndex: NumGet(Ptr + 4, "UInt")
                  ; A pointer to the next adapter addresses structure in the list
                  , Next: NumGet(Ptr + 8, "UPtr")
                  ; An array of characters that contains the name of the adapter with which these addresses are associated
                  , AdapterName: StrGet(NumGet(Ptr + 8 + A_PtrSize, "UPtr"), "UTF-8")
                  ; A pointer to the first IP_ADAPTER_UNICAST_ADDRESS structure in a linked list of IP unicast addresses for the adapter
                  , PIP_ADAPTER_UNICAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*2, "UPtr")
                  ; A pointer to the first IP_ADAPTER_ANYCAST_ADDRESS structure in a linked list of IP anycast addresses for the adapter
                  , PIP_ADAPTER_ANYCAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*3, "UPtr")
                  ; A pointer to the first IP_ADAPTER_MULTICAST_ADDRESS structure in a list of IP multicast addresses for the adapter
                  , PIP_ADAPTER_MULTICAST_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*4, "UPtr")
                  ; A pointer to the first IP_ADAPTER_DNS_SERVER_ADDRESS structure in a linked list of DNS server addresses for the adapter
                  , PIP_ADAPTER_DNS_SERVER_ADDRESS: NumGet(Ptr + 8 + A_PtrSize*5, "UPtr")
                  ; The Domain Name System (DNS) suffix associated with this adapter
                  , DnsSuffix: StrGet(NumGet(Ptr + 8 + A_PtrSize*6, "UPtr"), "UTF-16")
                  ; A description for the adapter. This member is read-only
                  , Description: StrGet(NumGet(Ptr + 8 + A_PtrSize*7, "UPtr"), "UTF-16")
                  ; A user-friendly name for the adapter. For example: "Local Area Connection 1." This name appears in contexts such as the ipconfig command line program and the Connection folder
                  , FriendlyName: StrGet(NumGet(Ptr + 8 + A_PtrSize*8, "UPtr"), "UTF-16")
                  ; The Media Access Control (MAC) address for the adapter. For example, on an Ethernet network this member would specify the Ethernet hardware address
                  , PhysicalAddress: Ptr + 8 + A_PtrSize*9
                  ; The length, in bytes, of the address specified in the PhysicalAddress member
                  , PhysicalAddressLength: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH, "UInt")
                  ; A set of flags specifying various settings for the adapter
                  , Flags: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4, "UInt")
                  ; The maximum transmission unit (MTU) size, in bytes
                  , Mtu: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*2, "UInt")
                  ; The interface type as defined by the Internet Assigned Names Authority (IANA)
                  , IfType: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*3, "UInt")
                  ; The operational status for the interface as defined in RFC 2863
                  , OperStatus: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*4, "Int")
                  ; The interface index for the IPv6 IP address. This member is zero if IPv6 is not available on the interface
                  , Ipv6IfIndex: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*5, "Int")
                  ; An array of scope IDs for each scope level used for composing sockaddr structures. The SCOPE_LEVEL enumeration is used to index the array. On IPv6, a single interface may be assigned multiple IPv6 multicast addresses based on a scope ID
                  , ZoneIndices: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6    ; DWORD[16]
                  , FirstPrefix: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16, "UPtr")
                  ; The current speed in bits per second of the transmit link for the adapter
                  , TransmitLinkSpeed: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize, "UInt64")
                  , ReceiveLinkSpeed: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8, "UInt64")
                  , FirstWinsServerAddress: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2, "UPtr")
                  , FirstGatewayAddress: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize, "UPtr")
                  , Ipv4Metric: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2, "UInt") }
                  ;, Ipv6Metric: NumGet(Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4, "UInt")
                  ;, Luid: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4*2    ; sizeof IF_LUID = 8
                  ;, Dhcpv4Server: Ptr + 8 + A_PtrSize*9 + MAX_ADAPTER_ADDRESS_LENGTH + 4*6 + 16 + A_PtrSize + 8*2 + A_PtrSize*2 + 4*2 + 8
                  ; ...

    Return Data
}


IP_ADAPTER_DNS_SERVER_ADDRESS(Ptr)
{
                  ; Reserved. Used by the compiler to align the structure
    Local Data := { Alignment: NumGet(Ptr+0, "UInt64")
                  ; The length, in bytes, of this structure
                  , Length: NumGet(Ptr+0, "UInt")
                  ; A pointer to the next adapter addresses structure in the list
                  , Next: NumGet(Ptr + 8, "UPtr")
				  , SAptr: NumGet(Ptr + 12, "UPtr")
				  , SAlength: NumGet(Ptr + 16, "UInt")}

    Return Data
				  
}


SOCKADDR(Ptr)
{

                  ; sa_familiy
    Local Data := { SAfamily: NumGet(Ptr+0, "USHORT")
                  ; ??? sa_data[14]
                  , sa_data: StrGet(Ptr + 2, 14, "char") }

    Return Data

	}
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 11:23

Code: Select all

ERROR_SUCCESS := 0
ERROR_BUFFER_OVERFLOW := 111

; #1, get required size
SizePointer := 0
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", 0, "UIntP", SizePointer)
If (Ret != ERROR_BUFFER_OVERFLOW)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

; #2, retrieves the addresses associated with the adapters on the local computer
; IP_ADAPTER_ADDRESSES structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366058(v=vs.85).aspx
VarSetCapacity(IP_ADAPTER_ADDRESSES, SizePointer)
; GetAdaptersAddresses function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
Ret := DllCall("Iphlpapi.dll\GetAdaptersAddresses", "UInt", 0, "UInt", 0, "Ptr", 0, "UPtr", &IP_ADAPTER_ADDRESSES, "UIntP", SizePointer)
If (Ret != ERROR_SUCCESS)
{
    MsgBox % "ERROR #" . Ret
    ExitApp
}

; https://msdn.microsoft.com/en-us/library/windows/desktop/ms741516(v=vs.85).aspx
VarSetCapacity(WSAData, A_PtrSize == 4 ? 400 : 408)
Ret := DllCall("Ws2_32.dll\WSAStartup", "UShort", 2, "UPtr", &WSAData, "UInt")
If (Ret != 0)
{
    MsgBox % "WSAStartup ERROR"
    ExitApp
}

PIP_ADAPTER_ADDRESSES := &IP_ADAPTER_ADDRESSES
While (PIP_ADAPTER_ADDRESSES)
{
    ; A pointer to the first IP_ADAPTER_DNS_SERVER_ADDRESS structure in a linked list of DNS server addresses for the adapter
    PIP_ADAPTER_DNS_SERVER_ADDRESS := NumGet(PIP_ADAPTER_ADDRESSES + 8 + A_PtrSize*5, "UPtr")
    While (PIP_ADAPTER_DNS_SERVER_ADDRESS)
    {
        ; The IP address for this DNS server entry. This member can be an IPv6 address or an IPv4 address.
        LPSOCKADDR := NumGet(PIP_ADAPTER_DNS_SERVER_ADDRESS + 8 + A_PtrSize, "UPtr")    ; SOCKET_ADDRESS.lpSockaddr
        Length := NumGet(PIP_ADAPTER_DNS_SERVER_ADDRESS + 8 + A_PtrSize*2, "UInt")    ; SOCKET_ADDRESS.iSockaddrLength

        ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms741516(v=vs.85).aspx
        sin_family := NumGet(LPSOCKADDR+0, "UShort")    ; sockaddr.sin_family
            ;AF_INET := 2      ; IPv4 address (192.168.16.0)
            ;AF_INET6 := 23    ; IPv6 address

        VarSetCapacity(String, 100)
        DllCall("Ws2_32.dll\WSAAddressToStringW", "UPtr", LPSOCKADDR, "UInt", Length, "UPtr", 0, "Str", String, "UIntP", 50)
        MsgBox % String

        ; A pointer to the next DNS server address structure in the list.
        PIP_ADAPTER_DNS_SERVER_ADDRESS := NumGet(PIP_ADAPTER_DNS_SERVER_ADDRESS + 8, "UPtr")
    }
           
    ; A pointer to the next adapter addresses structure in the list
    PIP_ADAPTER_ADDRESSES := NumGet(PIP_ADAPTER_ADDRESSES + 8, "UPtr")
}
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 11:39

Haha thanks Helgef. I just have fun with DllCall. :)
Although this structure is giving me headaches. :headwall:
rsilvestri
Posts: 4
Joined: 07 May 2018, 16:55

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 12:12

Great job also from my side. :clap: :clap: :clap:

I tried to incorporate the changes to my code, but lack to understand on why my DllCall returns the -1. Even once I take your statement 1:1 into my code having the variables populated with adequate values, I still get the -1. :cry:

Code: Select all

	LPSOCKADDR := IP_ADAPTER_DNS_SERVER_ADDRESS.LPSOCKADDR
	SAlength := IP_ADAPTER_DNS_SERVER_ADDRESS.SAlength
	VarSetCapacity(String, 100)
	Res := DllCall("Ws2_32.dll\WSAAddressToStringW", "UPtr", LPSOCKADDR+0, "UInt", SAlength, "UPtr", 0, "Str", String, "UIntP", 50)
	If (Res != ERROR_SUCCESS)
	{
		MsgBox % "ERROR #" . Res . " / LPSOCKADDR: " . LPSOCKADDR . " / SAlength: " . SAlength . " / IPSTRlength: " . IPSTRlength . " / test: " . String
		ExitApp
	}
Any idea about the reason?
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 13:19

Flipeador, do you have code which retrieves a pointer to such a memory location?
This structure is not a true C-language structure because it contains variable-length members. This structure was created solely to depict the organization of data in a version resource and does not appear in any of the header files shipped with the Windows Software Development Kit (SDK).
:?
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

Re: unable to read IP_ADAPTER_UNICAST_ADDRESS substructure of GetAdaptersAddresses DLL call

13 May 2018, 13:28

I know that. I'm writing my own v2 compiler, and I just need add support to change the version info (I'm not willing to use external applications!). I retrieve the VS_VERSIONINFO structure reading the resource of the executable. But as you can see, it has several variable-length members, and need padding. I'm on it. I'll make it work :think: .
Edit* I have done it. It only needs a few editions. ;)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Rohwedder and 175 guests