DLLCall - Ausgabe eines structs, welches als Element ein struct beinhaltet, klappt! Elegante Lösung zum Auslesen der Daten gesucht

  • Hey Leute,
    die Funktion, die ich definiert habe verwendet die DISM API und ruft folgende Funktion darin auf:

    Das zurückgegeben struct sieht so aus:

    Das Element "SYSTEMTIME" beschreibt ein struct und an dieser Stelle entsteht auch mein Problem. Das struct Systemtime ist schon standardmäßig definiert und wird z.B. für

    [autoit]

    _Date_Time_GetSystemTime

    [/autoit]


    verwendet. Habe dazu einfach Date.au3 included. So sieht's aus:

    [autoit]

    ; #STRUCTURE# ===================================================================================================================
    ; Name...........: $tagSYSTEMTIME
    ; Description ...: Specifies a date and time, in coordinated universal time (UTC)
    ; Fields ........: Year - Year
    ; Month - Month
    ; Dow - Day of week
    ; Day - Day
    ; Hour - Hour
    ; Minute - Minute
    ; Second - Second
    ; MSeconds - MSeconds
    ; Author ........: Paul Campbell (PaulIA)
    ; Remarks .......:
    ; ===============================================================================================================================
    Global Const $tagSYSTEMTIME = "struct;word Year;word Month;word Dow;word Day;word Hour;word Minute;word Second;word MSeconds;endstruct"

    [/autoit]


    Mein code:

    [autoit]

    Func _DISM_GetDrivers($Session, $AllDrivers = False)

    Local $tmp_tagDismDriverPackage, $DriverPackage, $Count
    Local $rParams = 15 ; count of return parameter

    Local $aResult = DllCall($ghdismapi, "LONG", "DismGetDrivers", _
    "PTR", $Session, _
    "BOOL", $AllDrivers, _
    "PTR*", $DriverPackage, _
    "UINT*", $Count _
    )
    If @error Or $aResult[0] <> $S_OK Then Return SetError(@error, @extended, Hex($aResult[0]))
    ;~ If @error Then Return SetError(@error, @extended, 0)
    ;~ Return SetExtended(_WinAPI_GetLastError(), Hex($aResult[0]))

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

    ;~ _ArrayDisplay($aResult)

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

    $DriverPackage = $aResult[3]
    $Count = 1;$aResult[4]

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

    Local $aReturn[$Count][$rParams]
    For $i = 1 To $Count
    $tmp_tagDismDriverPackage &= $tagDismDriverPackage
    If $i = $Count Then ExitLoop
    $tmp_tagDismDriverPackage &= ";"
    Next

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

    Local $stString = DllStructCreate($tmp_tagDismDriverPackage, $DriverPackage)
    ConsoleWrite("error: " & @error & @CRLF)
    _DLLStructDisplay($stString, $tmp_tagDismDriverPackage)

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

    $k = 0
    For $i = 1 To $Count
    For $j = 1 To $rParams
    $k += 1
    If BitOR($j = 1, $j = 2, $j = 4, $j = 5, $j = 6, $j = 7, $j = 10) Then
    $tmp_stString = DllStructCreate("WCHAR [260]", DllStructGetData($stString, $k))
    $aReturn[$i-1][$j-1] &= DllStructGetData($tmp_stString, 1)
    ContinueLoop
    ElseIf $j = 11 Then
    MsgBox(0, "asdad", $k)
    $tmp_stString = DllStructCreate($tagSYSTEMTIME, DllStructGetData($stString, $k))
    ;~ ConsoleWrite("date: " & _Date_Time_SystemTimeToDateTimeStr($tmp_stString) & @CRLF)
    _DLLStructDisplay($tmp_stString, $tagSYSTEMTIME)
    $aReturn[$i-1][$j-1] &= _Date_Time_SystemTimeToDateTimeStr($tmp_stString)
    ContinueLoop
    EndIf
    $aReturn[$i-1][$j-1] &= DllStructGetData($stString, $k)
    Next
    Next

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

    ; free resources
    _DISM_Delete($stString)
    _DISM_Delete($tmp_stString)

    _Arraydisplay($aReturn)
    Return SetExtended(_WinAPI_GetLastError(), $aReturn)
    EndFunc ;==>_DISM_GetDrivers

    [/autoit]

    Soweit stimmt alles, aber ich bekomme es nicht hin, die "SYSTEMTIME" vernünftig auszugeben. Die beiden Structs sehen so aus:
    Struct 1:
    [Blockierte Grafik: http://imageshack.us/a/img248/6586/struct1.png]
    Struct 2:
    [Blockierte Grafik: http://imageshack.us/a/img4/8963/struct2.png]
    Der Return so:
    [Blockierte Grafik: http://imageshack.us/a/img706/9121/return1.png]

    Im zweiten strcut sollte jetzt eigentlich 21.06.2006 stehen, denn wenn ich das Kommandozeilen Programm von Dism benutze und mir die Driver Info von oem0.inf ausgeben lasse zeigt er es so an:
    [Blockierte Grafik: http://imageshack.us/a/img267/4740/dismexeoutput.png]

    Hat jemand eine Idee, warum das Datum nicht korrekt zurückgegeben bzw. ausgegeben wird???

    Vielen Danke schonmal jungs!

    4 Mal editiert, zuletzt von Trolleule1337 (7. Februar 2013 um 15:39)

  • Zitat

    Soweit stimmt alles,

    sicher?
    UINT MajorVersion;
    UINT MinorVersion;
    UINT Build;
    UINT Revision
    haben, so weit ich das sehe (Screenshot 1), nichts mit den Angaben auf deinem Screenshot zur Treiberpaketinformation zu tun.

    Bist du definitiv sicher, dass die Struct SYSTEMTIME aus der DismGetDriverInfo () identisch ist mit der Struct aus _Date_Time_GetSystemTime() ?

  • Grüß dich,
    sehr gut beobachtet Andy! Ja du hast recht die sind auch net richtig, aber ich finde das Thema schon recht schwierig und wollte es nicht noch komplizierter machen, daher habe ich das erstmal außen vorgelassen. Wo wir gerade dabei sind. Ich habe mir die Treiberdatei angesehen und dort gibt es keine Information zu "MajorVersion", "MinorVersion", "Build" und "Revision". Das ist schon ziemlich komisch. Weiß nicht mal woher er die Daten für Revision und "MajorVersion" hernimmt. Naja es sei denn, "6.1.7600.16385" soll die MajorVersion sein.

    Ich kann nicht sagen ob es die selbe SYSTEMTIME wie aus _Date_Time_GetSystemTime() ist, ich habe zwar die dismapi.h Datei, dort ist es aber nicht definiert worden, daher nehme ich an es wird die "Global" definierte SYSTEMTIME verwendet. Kann ich das irgendwie nachprüfen???

    EDIT:
    Was auch komisch ist: Ich habe $Count auf 1 gesetzt, damit er erstmal nur 1 Treiber einliest. Habe jetzt mal die ausgelesene Anzahl genommen (2 Treiber) und das Struct sieht sehr merkwürdig aus:

    Struct für 2 Treiber:
    [Blockierte Grafik: http://img843.imageshack.us/img843/2226/bild5mg.png]

    InBox dürfte z.B. nur 0 oder 1 sein!!!
    AutoIT stürzt auch bei jedem 2ten mal ab.

    Achja ganz vergessen:
    Meine Definition vom DismDriverPackage struct:

    [autoit]

    ; DismDriverPackage
    Global Const $tagDismDriverPackage = "PTR PublishedName;PTR OriginalFileName;BOOL InBox;PTR CatalogFile;PTR ClassName;PTR ClassGuid;PTR ClassDescription;" & _
    "BOOL BootCritical;INT DriverSignature;PTR ProviderName;PTR Date;UINT MajorVersion;UINT MinorVersion;UINT Build;UINT Revision"

    [/autoit]
  • Hi!

    Zitat

    Ja du hast recht die sind auch net richtig, aber ich finde das Thema schon recht schwierig und wollte es nicht noch komplizierter machen,

    Dein Problem ist, dass du keine GENAUE Beschreibung der DLL hast. Bis zum Datum stimmen die Ergebnisse, ab dann nicht mehr. Die DLL schreibt natürlich einfach nur "ihre" Daten fortlaufend in den Speicher (an der Position der Struct) . Wenn du diesen Speicherbereich natürlich nur teilweise ausliest, dann geht das nur so lange gut, bis du an (wie in diesem Fall das DATE) einen Punkt gelangst, an dem du nur RÄTST, was die nächsten Bytes in der Struct enthalten.
    Stimmt wenigstens die Bytelänge deiner Abfrage, bekommst du zwar ein "falsches" Ergebnis, bpw. die DLL schreibt FLOAT und du liest INT (beides 4 bytes), aber die folgenden Daten sind wieder "richtig".
    Ich sehe gerade deine

    [autoit]

    Global Const $tagDismDriverPackage = "PTR PublishedName;PTR OriginalFileName;BOOL InBox;PTR CatalogFile;PTR ClassName;PTR ClassGuid;PTR ClassDescription;" & _
    "BOOL BootCritical;INT DriverSignature;PTR ProviderName;PTR Date;UINT MajorVersion;UINT MinorVersion;UINT Build;UINT Revision"

    [/autoit]


    PTR Date stimmt ja mal nicht mit SYSTEMTIME Date; überein!
    trag doch statt dessen die struct $tagSYSTEMTIME dafür ein.

    [autoit]

    Global Const $tagDismDriverPackage = "PTR PublishedName;PTR OriginalFileName;BOOL InBox;PTR CatalogFile;PTR ClassName;PTR ClassGuid;PTR ClassDescription;" & _
    "BOOL BootCritical;INT DriverSignature;PTR ProviderName;"&$tagSYSTEMTIME&";UINT MajorVersion;UINT MinorVersion;UINT Build;UINT Revision"

    [/autoit]

    so würde ich es versuchen

    //EDIT

    Zitat

    AutoIT stürzt auch bei jedem 2ten mal ab.

    kein Wunder, du reservierst mit deiner Struct nur XX Bytes, aber die DLL schreibt YY Bytes "über" das Ende der Struct. Werden diese Bytes anderweitig belegt bzw benutzt, dann kracht es natürlich.

  • HAHAH fuck man, du bist genial Andy! Es klappt! Aber ich dachte wirklich er gibt mir den Pointer von dem struct SYSTEMTIME zurück, ist aber nicht so! Jetzt sehen die anderen Elemente auch schon viel besser aus!

    Danke!!! :love:

  • Also die Funktion funktioniert nun. Aber meine Lösung zum Auslesen der Daten und strukturieren des Arrays wirkt auf mich weniger elegant gelöst und unsauber programmiert. Das hier ist meine beste Lösung, die ich gefunden habe, was meint ihr?:

    [autoit]

    Func _DISM_GetDrivers($Session, $AllDrivers = False)

    Local $aStDataTypes = StringSplit($tagDismDriverPackage, ';')

    Local $getSystemTime = DllStructCreate($_tagSYSTEMTIME)

    Local $tmp_tagDismDriverPackage, $tmp_stString, $DriverPackage, $Count
    Local $aParams = 12 ; count of return parameter in array
    Local $DriverPackageInfo = 10 ; part one of struct
    Local $Date = 8 ; part two of struct
    Local $DriverVersion = 4 ; part three of struct

    Local $aResult = DllCall($ghdismapi, "LONG", "DismGetDrivers", _
    "PTR", $Session, _
    "BOOL", $AllDrivers, _
    "PTR*", $DriverPackage, _
    "UINT*", $Count _
    )
    If @error Or $aResult[0] <> $S_OK Then Return SetError(@error, @extended, Hex($aResult[0]))

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

    $DriverPackage = $aResult[3]
    $Count = $aResult[4]

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

    Local $aReturn[$Count][$aParams]
    For $i = 1 To $Count
    $tmp_tagDismDriverPackage &= $tagDismDriverPackage
    If $i = $Count Then ExitLoop
    $tmp_tagDismDriverPackage &= ";"
    Next

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

    Local $stString = DllStructCreate($tmp_tagDismDriverPackage, $DriverPackage)

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

    $k = 0

    For $i = 1 To $Count
    Local $index = 0
    Local $Version = ""
    For $j = 1 To $DriverPackageInfo
    $k += 1
    $index += 1
    If StringInStr($aStDataTypes[$j], "PTR") <> 0 Then
    ConsoleWrite("ptr: " & $j & @CRLF)
    $tmp_stString = DllStructCreate("WCHAR [260]", DllStructGetData($stString, $k))
    $aReturn[$i-1][$index-1] &= DllStructGetData($tmp_stString, 1)
    ContinueLoop
    EndIf
    $aReturn[$i-1][$index-1] &= DllStructGetData($stString, $k)
    Next

    For $j = 1 To $Date
    $k += 1
    DllStructSetData($getSystemTime, $j, DllStructGetData($stString, $k))
    Next
    $index += 1
    $aReturn[$i-1][$index-1] &= _Date_Time_SystemTimeToDateStr($getSystemTime)

    For $j = 1 To $DriverVersion
    $k += 1
    $Version &= DllStructGetData($stString, $k)
    If $j = $DriverVersion Then ExitLoop
    $Version &= "."
    Next
    $index += 1
    $aReturn[$i-1][$index-1] &= $Version
    Next

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

    ; free resources
    _DISM_Delete($stString)
    _DISM_Delete($tmp_stString)

    _Arraydisplay($aReturn)
    Return SetExtended(_WinAPI_GetLastError(), $aReturn)
    EndFunc ;==>_DISM_GetDrivers

    [/autoit]

    Das gesamte struct sieht so aus:
    [Blockierte Grafik: http://imageshack.us/a/img849/8476/structall.png]

    Das struct hat 22 Parameter und es kommen jeweils weitere 22 Parameter dazu, abhängig von der Anzahl der Treiber die in $Count gespeichert werden. Deshalb brauchte ich auch eine fortlaufende Zahl ($k).

    Mein Array sieht nun so aus:
    [Blockierte Grafik: http://imageshack.us/a/img46/9683/arraylast.png]

    Vielen Dank für eure Hilfe Leute!