Iphlpapi.dll/GetAdaptersInfo liefert mit 64bit-Compilat bei LeaseObtained u. LeaseExpires immer 0

  • Hallo Zusammen,

    in der Vergangenheit habe ich die Infos für die Netzwerkadapter immer mittels WMI und Win32_NetworkAdapterConfiguration ausgelesen, doch bei z.B. mürben Nvidia-Treibern wurde oft bei IP, Subnetmask etc immer "" zurückgeliefert. Daher bin ich auf der Suche nach einer Alternative und bin auf da Script GetAdaptersXML.au3 von ProgAndy gestossen.

    Ich hab es leicht modifiziert und als x32 und x64 compiliert und ausprobiert. Doch leider liefert das x64-Compilat immer 0 bei LeaseObtained und LeaseExpires. Der Rest sieht gut aus.

    Jetzt habe ich ne Nacht darüber geschlafen, aber ich finde heute auch nicht die Ursache dafür. Die Structur sieht sauber aus, der Aufruf auch. Hat jemand ne Idee, was da faul ist?

    Spoiler anzeigen


    Besten Dank im voraus!
    R@iner

    PS: Ergänzung: Das x86-Compilat liefert die richtigen Werte auf einem x64-OS, z.B. Win 7 Ultimate.

    Einmal editiert, zuletzt von skyteddy (12. April 2011 um 15:36)

  • Auf jeden Fall müsste das in der Definition so lauten:
    "DWORD_PTR LeaseObtained; DWORD_PTR LeaseExpires;"

  • Huch, wieso dass denn? Einen PTR? Bist Du Dir sicher?

    Ich hab jetzt mal in der MSDN nachgeschaut. Dort steht Type: time_t.

    Und weiter unten:
    When using Visual Studio 2005 and later, the time_t datatype defaults to an 8-byte datatype, not the 4-byte datatype used for the LeaseObtained and LeaseExpires members on a 32-bit platform. To properly use the IP_ADAPTER_INFO structure on a 32-bit platform, define _USE_32BIT_TIME_T (use -D _USE_32BIT_TIME_T as an option, for example) when compiling the application to force the time_t datatype to a 4-byte datatype.

    Das heißt jetzt was genau? DWORD in AutoIt ist doch ein unsigned 32 bit integer. Oder braucht das nun auf x64 eine UINT64?

    Happy computing!
    R@iner

  • DWORD_PTR bedeutet eine vorzeichenlose Zahl in der größe eine Pointers, also 32bit auf x86 und 64bit auf x64. Das heißt nicht, dass es ein Pointer ist.
    In der Struktur müsste es eigentlich time_t sein, aber das gibt es in AutoIt nicht. time_t ist mit Windows auf x86 32bit und auf x64 64bittig. Also ist DWORD_PTR passend. (Bei x86/32bit machen neue Compiler auch 64bit, das Zitat von dir sagt aber eindeutig, dass auf 32bit-Systemen ein 32bit-Feld erwartet wird)

  • Hello again,

    danke, jetzt versteh ich auch DWORD_PRT. Ich hab das Script modifiziert und als x64 und x32 compiliert und aufgerufen. Das kommt raus:

    ipconfig:
    Lease erhalten. . . . . . . . . . : Dienstag, 12. April 2011 17:33:39
    Lease läuft ab. . . . . . . . . . : Freitag, 22. April 2011 17:33:39

    32bit:
    <LEASEOBTAINED>2011/04/12 15:33:39</LEASEOBTAINED>
    <LEASEEXPIRES>2011/04/22 15:33:39</LEASEEXPIRES>

    64bit:
    <LEASEOBTAINED>1970/01/01 00:00:00</LEASEOBTAINED>
    <LEASEEXPIRES>2011/04/12 15:33:39</LEASEEXPIRES>

    Irgendwas stimmt nicht, beim x64. Im LeaseExpires-Feld steht jetzt das Datum von LeaseObtained :(

    Happy computing!
    R@iner

  • Man, das ist ein Alignment-Problem mit dem Substrukturen-workaround auf x64.

    So könnte es klappen:

    Spoiler anzeigen
    [autoit]

    Opt("MustDeclareVars",1)

    [/autoit] [autoit][/autoit] [autoit]

    ; ProgAndy
    Func _GAXML_SubStruct_GetSize($tagSUBSTRUCT)
    Return DllStructGetSize(DllStructCreate($tagSUBSTRUCT, 1))
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; ProgAndy
    Func _GAXML_SubStruct_Get(ByRef $tSTRUCT, $vElement, Const $tagSUBSTRUCT)
    Local $pTarget = DllStructGetPtr($tSTRUCT, $vElement)
    If @error Or $pTarget = 0 Then Return SetError(1,0,0)
    Local $tSUBSTRUCT = DllStructCreate($tagSUBSTRUCT, $pTarget)
    If @error Then Return SetError(2,@error, 0)
    Return $tSUBSTRUCT
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; ProgAndy
    Func _GAXML_SubStruct_Declare($tagSUBSTRUCT, $sName="")
    If $sName = "" Then Return "byte[" & _GAXML_SubStruct_GetSize($tagSUBSTRUCT) & "];"
    Return "byte " & $sName & "[" & _GAXML_SubStruct_GetSize($tagSUBSTRUCT) & "];"
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _GAXML_XML_Encode($val)
    Return StringReplace(StringReplace(StringReplace($val, "&", "&#x26;"), "<", "&#x3c"), ">", "&#x3e")
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _GAXML_XML_MakeNode($tag, $val)
    If StringLen($val) = 0 Then Return "<" & StringUpper($tag) & "></" & StringUpper($tag) & ">" & @CRLF
    ;~ ConsoleWrite($tag & "=" & $val & @CRLF)
    Return "<" & StringUpper($tag) & ">" & _GAXML_XML_Encode($val) & "</" & StringUpper($tag) & ">" & @CRLF
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _GAXML_GetXML(ByRef $Struct, $Name)
    Local $val = DllStructGetData($Struct,$Name)
    If @error Then Return _GAXML_XML_MakeNode($Name, "")
    Return _GAXML_XML_MakeNode($Name, $val)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $tagIP_ADDRESS_STRING = "char IPAddress[16];"
    Global Const $tagIP_MASK_STRING = "char IPMask[16];"
    Global Const $tagIP_ADDR_STRING = "ptr Next;" & $tagIP_ADDRESS_STRING & $tagIP_MASK_STRING & "DWORD Context;"

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $tagIP_ADAPTER_INFO = "ptr Next; DWORD ComboIndex; char AdapterName[260];char Description[132]; UINT AddressLength; BYTE Address[8]; dword Index; UINT Type;" & _
    " UINT DhcpEnabled; ptr CurrentIpAddress; " & _GAXML_SubStruct_Declare($tagIP_ADDR_STRING, "IpAddressList") & _
    _GAXML_SubStruct_Declare($tagIP_ADDR_STRING, "GatewayList") & _
    _GAXML_SubStruct_Declare($tagIP_ADDR_STRING, "DhcpServer") & _
    "int HaveWins; " & _
    _GAXML_SubStruct_Declare($tagIP_ADDR_STRING, "PrimaryWinsServer") & _
    _GAXML_SubStruct_Declare($tagIP_ADDR_STRING, "SecondaryWinsServer") & _
    "DWORD_PTR LeaseObtained; DWORD_PTR LeaseExpires;"

    [/autoit] [autoit][/autoit] [autoit]

    Func _GetMac(ByRef $tInfo)
    Local $BinaryMAC = BinaryMid(DllStructGetData($tInfo,"Address"),1,DllStructGetData($tInfo,"AddressLength"))
    Return StringTrimRight(StringRegExpReplace(StringTrimLeft($BinaryMAC,2),"([[:xdigit:]]{2})","$1:"),1)
    EndFunc
    Func net_getMACIDFromIP($ip_addr)
    Local $MAC_struct = DllStructCreate("byte[6]")
    Local $MAC_size = DllStructCreate("int")
    DllStructSetData($MAC_size, 1, 6)
    Local $rc = DllCall("Ws2_32.dll", "int", "inet_addr", "str", $ip_addr)
    Local $in_addr = $rc[0]
    $rc = DllCall("iphlpapi.dll", "int", "SendARP", "int", $in_addr, "int", 0, "ptr", DllStructGetPtr($MAC_struct), "ptr", DllStructGetPtr($MAC_size))
    If $rc[0] <> 0 Then Return ""
    Local $str = ""
    For $i = 1 To 6
    If $i > 1 Then $str = $str & ":"
    $str &= Hex(DllStructGetData($MAC_struct, 1, $i), 2)
    Next
    Return $str
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $NETWORK_REG_KEY = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\"

    [/autoit] [autoit][/autoit] [autoit]

    Local $dll = DllOpen("Iphlpapi.dll")
    Local $ret = DllCall($dll, "dword", "GetAdaptersInfo", "ptr", 0, "dword*", 0)

    [/autoit] [autoit][/autoit] [autoit]

    Local $adapterBuffer = DllStructCreate("byte[" & $ret[2] & "]")
    Local $adapterBuffer_pointer = DllStructGetPtr($adapterBuffer)
    Local $return = DllCall($dll, "dword", "GetAdaptersInfo", "ptr", $adapterBuffer_pointer, "dword*", $ret[2])
    Local $adapter = DllStructCreate($tagIP_ADAPTER_INFO, $adapterBuffer_pointer)
    If Not @error Then
    Local $DisplayName,$ptr,$adapter,$adapterName,$MediaSubType,$PnpInstanceID
    Local $XML='<?xml version="1.0" encoding="UTF-8"?>'&@CRLF&"<ADAPTERS>"&@CRLF&@CRLF
    Do
    $XML &= " <ADAPTER>" & @CRLF
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "ComboIndex")
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "Description")
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "AdapterName")
    $XML &= @TAB & @TAB & _GAXML_XML_MakeNode("Address", _GetMac($adapter) )
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "Index")
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "Type")
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "DhcpEnabled")
    $XML &= _GetAllIPsXML(DllStructGetPtr($adapter, "IpAddressList"), "IP", False)
    $XML &= _GetAllIPsXML(DllStructGetPtr($adapter, "GatewayList"), "Gateway")
    $XML &= _GetFirstIPXML(DllStructGetPtr($adapter, "DhcpServer"), "DhcpServer")
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "HaveWins")
    $XML &= _GetFirstIPXML(DllStructGetPtr($adapter, "PrimaryWinsServer"), "PrimaryWinsServer")
    $XML &= _GetFirstIPXML(DllStructGetPtr($adapter, "SecondaryWinsServer"), "SecondaryWinsServer")
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "LeaseObtained")
    $XML &= @TAB & @TAB & _GAXML_GetXML($adapter, "LeaseExpires")

    [/autoit] [autoit][/autoit] [autoit]

    $adapterName = DllStructGetData($adapter, "AdapterName")
    $DisplayName = RegRead($NETWORK_REG_KEY & $adapterName & "\Connection", "Name")
    $XML &= @TAB & @TAB & _GAXML_XML_MakeNode("DisplayName", $DisplayName)
    $MediaSubType = RegRead($NETWORK_REG_KEY & $adapterName & "\Connection", "MediaSubType")
    $XML &= @TAB & @TAB & _GAXML_XML_MakeNode("MediaSubType", $MediaSubType)
    ConsoleWrite("+-> Mediasubtype: ( LAN = 1 oder 10 ?why? ; Network-Bridge = 1(aber auch LAN?why) ; WLAN = 2 ; IEEE1394 = 5 ; Bluetooth = 9 ; )"&@CRLF)
    $PnpInstanceID = RegRead($NETWORK_REG_KEY & $adapterName & "\Connection", "PnpInstanceID")
    $XML &= @TAB & @TAB & _GAXML_XML_MakeNode("PnpInstanceID", $PnpInstanceID)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $XML &= " </ADAPTER>" & @CRLF & @CRLF
    $ptr = DllStructGetData($adapter, "Next")
    $adapter = DllStructCreate($tagIP_ADAPTER_INFO, $ptr)
    Until @error
    $XML &= "</ADAPTERS>"&@CRLF
    EndIf
    ConsoleWrite($XML & @CRLF)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _GetAllIPsXML($Ptr, $Type, $MAC=True, $Indent=2)
    Local $Tab=""
    For $i = 1 To $Indent
    $Tab &= @TAB
    Next
    Local $return = $Tab & "<"&StringUpper($Type) & "LIST>"&@CRLF
    Local $IPArray = _GetAllIps($Ptr)
    For $i = 0 To UBound($IPArray)-1
    $return &= $Tab & " <" & StringUpper($Type)&">" & @CRLF
    $return &= $Tab & " " & _GAXML_XML_MakeNode($Type&"_IP", $IPArray[$i][0])
    $return &= $Tab & " " & _GAXML_XML_MakeNode($Type&"_MASK", $IPArray[$i][1])
    $return &= $Tab & " " & _GAXML_XML_MakeNode($Type&"_CONTEXT", $IPArray[$i][2])
    If $MAC Then $return &= $Tab & " " & _GAXML_XML_MakeNode($Type&"_MAC", net_getMACIDFromIP($IPArray[$i][0]))
    $return &= $Tab & " </" & StringUpper($Type)&">" & @CRLF
    Next
    $return &= $Tab & "</"&StringUpper($Type) & "LIST>"&@CRLF
    Return $return
    EndFunc
    Func _GetFirstIPXML($Ptr, $Type, $MAC=True, $Indent=2)
    Local $Tab=""
    For $i = 1 To $Indent
    $Tab &= @TAB
    Next
    Local $IPStruct = DllStructCreate($tagIP_ADDR_STRING,$ptr)
    Local $return = $Tab & "<" & StringUpper($Type)&">" & @CRLF
    $return &= $Tab & @TAB & _GAXML_XML_MakeNode($Type&"_IP", DllStructGetData($IPStruct,"IPAddress"))
    $return &= $Tab & @TAB & _GAXML_XML_MakeNode($Type&"_MASK", DllStructGetData($IPStruct,"IPMask"))
    $return &= $Tab & @TAB & _GAXML_XML_MakeNode($Type&"_CONTEXT", DllStructGetData($IPStruct,"Context"))
    If $MAC Then $return &= $Tab & @TAB & _GAXML_XML_MakeNode($Type&"_MAC", DllStructGetData($IPStruct,"IPAddress"))
    $return &= $Tab & "</" & StringUpper($Type)&">" & @CRLF
    Return $return
    EndFunc
    Func _GetAllIps($Ptr)
    Local $IPStruct, $Index = 0
    Local $IPArray[1][3]
    Do
    ReDim $IPArray[$Index+1][3]
    $IPStruct = DllStructCreate($tagIP_ADDR_STRING,$ptr)
    $IPArray[$Index][0] = DllStructGetData($IPStruct,"IPAddress")
    $IPArray[$Index][1] = DllStructGetData($IPStruct,"IPMask")
    $IPArray[$Index][2] = DllStructGetData($IPStruct,"Context")
    $Ptr = DllStructGetData($IPStruct,"Next")
    $Index += 1
    Until $Ptr = 0
    Return $IPArray
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    $adapterBuffer = ""
    $adapterBuffer_pointer = ""
    DllClose($dll)

    [/autoit]
  • Dank Dir!

    Da Du es auf Basis Deines alten Beispiels gemacht hast, muss ich erst mal genau schauen, wo Du welche Änderung (und vor allem warum) gemacht hast.
    Nichts für heute Abend, das wird ne Zeit dauern

    Dank Dir und happy computing!
    R@iner

    2 Mal editiert, zuletzt von skyteddy (12. April 2011 um 20:09)

  • @progandy:
    Damit ich das auch verstehe ... ist der Aufwand jetzt notwendig, weil der Compiler für x64 mürbe ist, oder ist das generell ein Problem bei der Verwendung von Structuren?
    Heißt das im Umkehrschluss, dass ich all meine Programm anpassen muß, die mit Structuren und Ptr auf Structuren arbeiten?

    Happy computing!
    R@iner

  • Wenn man nur mit einfachen Strukturen und Pointern auf Strukturen arbeitet, dann gibt es keine Probleme. Wenn jedoch eine Struktur eine andere Struktur direkt beinhaltet ohne Pointer, dann ist es sehr wahrscheinlich, dass du in Zukunft diese Funktionen verwenden musst.
    Das liegt aber nicht am Compiler, es ist nur Zufall, dass es bisher funktioniert hat. Der eigentliche Grund ist, dass AutoIt Strukturen als Elemente von Strukturen nicht direkt unterstützt.

  • Wenn man nur mit einfachen Strukturen und Pointern auf Strukturen arbeitet, dann gibt es keine Probleme. Wenn jedoch eine Struktur eine andere Struktur direkt beinhaltet ohne Pointer, dann ist es sehr wahrscheinlich, dass du in Zukunft diese Funktionen verwenden musst.


    Ich hab jetzt verstanden, was Du da machst. Da ich aber ein Array füllen will, schmeiss ich das xml-Zeugs eh raus.

    Zitat

    Das liegt aber nicht am Compiler, es ist nur Zufall, dass es bisher funktioniert hat. Der eigentliche Grund ist, dass AutoIt Strukturen als Elemente von Strukturen nicht direkt unterstützt.


    Den Satz habe ich nicht ganz verstanden :( Es wird doch zur Laufzeit eine Structur erzeugt, und dementsprechend lang sollten doch die einzelnen Objecte werden. Ein DWORD_PTR ist halt je nach Architektur, dann halt einmal x Bytes groß und auf der x64 Architektur y Bytes groß.

    Oder wo ist da mein Denkfehler?

    Gruß
    R@iner

  • Den Satz habe ich nicht ganz verstanden :( Es wird doch zur Laufzeit eine Structur erzeugt, und dementsprechend lang sollten doch die einzelnen Objecte werden. Ein DWORD_PTR ist halt je nach Architektur, dann halt einmal x Bytes groß und auf der x64 Architektur y Bytes groß.


    Wenn du dir die Struktur IP_ADAPTER_INFO anschaust, dann hat diese mehrere Strukturen des Typs IP_ADDR_INFO als Elemente. Bisher hatte dann einfach die einzelnen Elemente von IP_ADDR_INFO direkt in IP_ADAPTER_INFO eingefügt. Dadurch wird aber das Alignment, d.h. die Ausrichtung der Elemente im Speicher leicht anders als wenn man erst IP_ADDR_INFO anordnet und dann den ganzen daraus entstehenden Speicherblock in IP_ADAPTER_INFO einordnet.
    Durch die SubStruct-Zusatzfunktionen habe ich das jetzt gelöst, indem ich die Größe der IP_ADDR_INFO-Info hole und dann den Speicherblock als byte-Array dieser Größe ausführe. Dieser wird dann korrekt angeordnet. Über _SubStruct_Get bekommt man dann eine AutoIt-DLLStruct, mit der man auf die Elemente zugreifen kann. (Im Skript hab ich diese jetzt nicht verwendet, das war mir zu viel Aufwand, das alte Skript daran anzupassen)

  • Dank Dir Andy, jetzt blick ich es langsam. Das Erzeugen der Structur hab ich verstanden, und das mit dem Alligment, aber das _SubStruct_Get geht mir ab :( Da muss ich mich erst noch reinfieseln. Ich hock gerade auf der Leitung. Ich glaub, ich schlaf erst mal drüber. :)

    Dank Dir und gute Nacht!
    R@iner