Speicherstelle auslesen. AutoIT stürzt ab

  • Hey,
    ich hab einen Pointer den ich einfach nicht ausgelesen bekomme.


    [autoit]

    Local $struct = DllStructCreate("WCHAR [4]", DllStructGetData($CustomProperty_struct, "Value"))

    [/autoit]

    $struct-Pointer: 0x00000005

    Hat jemand eine Idee mit welchem Dateityp bzw. mit welcher Größe ich den Wert auslesen kann?

    Hier die Struktur: http://msdn.microsoft.com/en-us/library/…p/hh824746.aspx

    Einmal editiert, zuletzt von Trolleule1337 (27. September 2013 um 21:00)

  • Bitte liefere ein komplettes Skript, welches dein Fehler reproduziert. So wird sich niemand ein Bild von deinem Problem machen können. Es gibt nämlich verschiedene Ursachen für dein Problem.

  • oki

    [autoit]

    Func _DISM_GetFeatureInfo($Session, $FeatureName, ByRef $CustomProperty, $Identifier = 0, $PackageIdentifier = 0, $OutputFormat = 0)

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

    ; control param passing
    Local $sType = "WSTR"
    If Not IsString($Identifier) And $Identifier = 0 Then $sType = "PTR"

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

    Local $aResult = DllCall($ghdismapi, "LONG", "DismGetFeatureInfo", _
    "PTR", $Session, _
    "WSTR", $FeatureName, _
    $sType, $Identifier, _
    "INT", $PackageIdentifier, _
    "PTR*", 0 _
    )
    If @error Then Return SetError(@error, @extended, 0)
    If IsArray($aResult) = 1 Then
    If $aResult[0] <> $S_OK Then Return SetError(@error, @extended, $aResult[0])
    EndIf

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

    Local $FeatureInfo = $aResult[5]

    ; get custom property data
    Local $CustomPropertyCount = DllStructGetData($FeatureInfo_struct, "CustomPropertyCount")
    If $CustomPropertyCount <> 0 Then
    Local $oCustomProperty_list = ObjCreate("System.Collections.ArrayList")
    ConsoleWrite("hier5" & @CRLF)
    For $properties = 1 To $CustomPropertyCount
    Local $oCustomProperty_dict = ObjCreate("Scripting.Dictionary") ; store custom property data in dictionay
    ; create DismCustomProperty Structure
    Local $CustomProperty_struct = DllStructCreate($tagDismCustomProperty, DllStructGetPtr($FeatureInfo_struct, DetermineLocation($tagDismCustomProperty, $properties, 1))) ; offset = 1
    Local $struct = DllStructCreate("WCHAR", DllStructGetData($CustomProperty_struct, "Value"))
    ConsoleWrite("hier" & DllStructGetData($struct, 1) & @CRLF) ; hier Fehler wegen Speicherzugriffsverletzung
    Next

    [/autoit]

    So sieht $CustomProperty_struct aus, siehe Anhang.

    Einmal editiert, zuletzt von Trolleule1337 (27. September 2013 um 20:59)

  • Hi,
    stimmts, du weisst noch nicht mal ansatzweise, was du tust.... ;(

    Überleg mal tief im Allerinnersten, an welcher Speicherstelle befindet sich die Adresse 0x00000005 ?

  • ich bin Fachinformatiker für Systemintegration :D :D :D

    wieso Speicherstelle, die juckt doch gar nicht. Der Wert ist 5. Aber es hapert an der Umsetzung, also wie ich die Daten richtig auslesen kann?

    Edit: So... habe nochmals ausgiebig getestet und viele Berechnungen durchgeführt und ich bin zum Ergebnis gekommen, dass ich ohne euch verloren bin. Was ich auch mache, AutoIT stürzt ab. Jetzt brauch ich euch Leute, bitte helft mir: Bitte nur aufzeigen wie ich den Wert auslesen kann!?

    Danke Freunde!

    2 Mal editiert, zuletzt von Trolleule1337 (28. September 2013 um 00:30)

  • Hi,

    Zitat

    wieso Speicherstelle, die juckt doch gar nicht. Der Wert ist 5.

    Du willst also ernsthaft behaupten, dass du als "Fachinformatiker für Systemintegration" keinerlei Probleme hast, von Speicherstelle 0x00000005 zu lesen?
    Vielleicht solltest du, bevor dich etwas "nicht juckt" deinen Fachinformatiker vergessen und dich mit dem Speichermanagement von Windows auseinandersetzen. Vielleicht wird dir dann ein Licht aufgehen, was an dieser Speicherstelle (und den folgenden ca. 500Kb) im Speicher steht :rolleyes:

    Zur Frage im Eingangspost:
    Ich würde anhand der Beschreibung "Value" vermuten, dass es sich bei 5 um einen Wert handelt. Habe bei msdn nicht mehr darüber gefunden....
    Die anderen beiden Speicherstellen sehen mir eher nach Pointern aus. Was ist damit?

  • Doch habe Probleme damit, ich weiß nicht weiter. Die anderen Elemente (Name und Path) auszulesen ist kein Problem, dafür habe ich deine Funktion aus dem anderen Thread verwendet.


    Aber Value, keine Chance, immer Absturz sobald ich mit DllStructGetData auf den Pointer zugreifen will.

    [autoit]

    Local $curElement = DllStructGetData(DllStructCreate("WCHAR", DllStructGetData($FeatureInfo_struct, "Value")), 1)

    [/autoit]

    Wenn ich DISM in der Befehlszeile verwenden bekomme ich als "Custom Properties"/"Benutzerdefinierte Eigenschaften" folgendes:

    Die Daten aus der DLL sehen so aus (aus meinem Array kopiert):

    Zitat

    [0]|FeatureName|FeatureState|DisplayName|Description|RestartRequired
    [1]|MediaCenter|InstallPending|Windows Media Center|Windows Media Center|Possible


    Custom Properties (ohne Value):

    Zitat

    [0]|Name|Path|
    [1]|MediaCenter|Windows Media Center

    Hab das Bild von dem Custom Property struct nochmal angehangen...

    Könnte im fehlenden Value, vllt. der Link stehen, andernfalls unterscheiden sich die Daten aus der DLL mit denen der Befehlszeile bzw. sind unvollständig?
    Hast du nicht eine Idee?

  • Hi,
    jetzt nochmal deutlich:
    An der Adresse 0x00000005 ist definitiv nichts, was dich interessieren könnte^^
    Von der Speicherstelle 0 bis die nächsten ca. 500Kb ist der gesamte Speicher belegt von....Windows!
    Daher kannst du dir die Finger wundtippen, dort bekommst du sicher keinen Zugriff auf irgendwelche Speicherstellen, denn Windows schützt natürlich seinen Code!
    Das sich das noch nicht rumgesprochen hat, wundert mich ehrlich gesagt!

    Zum Topic:
    Frag doch einfach im Entwicklerforum von M$ nach, was die mit Value meinen!
    Jedenfalls ist die 5 nichts, was irgendeinen Speicherplatz adressieren sollte^^
    Vielleicht die Nummer des Properties oder wasweisich....

  • Hab den Fehler gefunden :thumbdown:

    [autoit]

    Local $CustomProperty_struct = DllStructCreate($tagDismCustomProperty, DllStructGetPtr($FeatureInfo_struct, DetermineLocation($tagDismCustomProperty, $properties, 1))) ; offset = 1

    [/autoit]


    Richtig ist:

    [autoit]

    Local $CustomProperty_struct = DllStructCreate($tagDismCustomProperty, DllStructGetData($FeatureInfo_struct, "CustomProperty"))

    [/autoit]

    Hab da was durcheinander gebracht. :S
    Naja jetzt bekomme ich als Daten, die, die auch die Kommandozeile zurückgibt...also den Link.

    Edit: Ab und zu stürzt AutoIt immernoch ab. Schau mal bitte, ob ich deine Funktion so richtig übernommen habe:

    [autoit]

    Func GetPCWSTR(ByRef $struct, $sElementName) ; avoids memory access conflicts
    Local $char_struct, $char
    Local $PCWSTR_struct = DllStructCreate("WCHAR [260]", DllStructGetData($struct, $sElementName))
    Local $ptr = DllStructGetPtr($PCWSTR_struct) ; get pointer
    _DISM_Delete($PCWSTR_struct) ; free resources
    ConsoleWrite($sElementName & @crlf)
    Local $i = $ptr ; counter for signs
    ; read memory location until end of string
    Do
    $char_struct = DllStructCreate("WCHAR", $i) ; get memory location
    $i += 1
    $char = DllStructGetData($char_struct, 1) ; read sign at position
    ConsoleWrite($char)
    Until $char = Chr(0) ; end of string
    Local $string_struct = DllStructCreate("WCHAR[" & Int($i - $ptr) & "]", $ptr) ; create struct with correct amount of bytes
    Return DllStructGetData($string_struct, 1)
    EndFunc

    [/autoit]

    $char gibt folgendes aus:

    Zitat

    h?t?t?p?:?/?/?g?o?.?m?i?c?r?o?s?o?f?t?.?c?o?m?/?f?w?l?i?n?k???L?i?n?k?I?D?=?>Exit code: -1073741819 Time: 24.042

    Also auf das 4-letzte Zeichen kann er nicht zugreifen ?(

    2 Mal editiert, zuletzt von Trolleule1337 (29. September 2013 um 03:58)

  • [autoit]


    $i += 2; Anstelle von $i += 1
    Int( $i - $ptr) / 2

    [/autoit]

    Einmal editiert, zuletzt von CentuCore (29. September 2013 um 13:27)

  • @CentuCore, wie kommst du darauf, es wird doch eine Struct von WCHAR erstellt!?

    @Trolleule,
    deine Funktion moppelt doppelt^^
    Mal zur Erklärung:
    Ziel ist, die Anzahl Zeichen zu finden, die in einem String stehen, dazu wird das terminierende NULL-Zeichen gesucht. Die Position des Strings ist bereits bekannt (Pointer auf eine Struct bzw. deren Element).
    Du musst also nur noch ab diesem Pointer die Anzahl der Zeichen lesen und aufaddieren, bis du zu einem Nullzeichen kommst.
    Den "unbekannten String" in eine struct zu kopieren und dort dann zu suchen ist unnötig. Ich hatte das in meinem Beispiel erstellt, um überhaupt erstmal einen String zu haben^^

    [autoit]

    Func GetPCWSTR(ByRef $struct, $sElementName) ; avoids memory access conflicts
    ;~ Local $char_struct, $char
    ;~ Local $PCWSTR_struct = DllStructCreate("WCHAR [260]", DllStructGetData($struct, $sElementName))
    ;~ Local $ptr = DllStructGetPtr($PCWSTR_struct) ; get pointer
    ;~ ; _DISM_Delete($PCWSTR_struct) ; free resources
    ;~ ConsoleWrite($sElementName & @crlf)
    Local $ptr = DllStructGetPtr($struct, $sElementName) ; counter for signs
    local $i=$ptr
    ; read memory location until end of string
    Do
    $char_struct = DllStructCreate("WCHAR", $i) ; get memory location
    $i += 1
    $char = DllStructGetData($char_struct, 1) ; read sign at position
    ConsoleWrite($char)
    Until $char = Chr(0) ; end of string
    Local $string_struct = DllStructCreate("WCHAR[" & Int($i-$ptr) & "]",$ptr) ; create struct with correct amount of bytes
    Return DllStructGetData($string_struct, 1)
    EndFunc

    [/autoit]

    Wenn du dir das Pointergedöns sparen möchtest, kannst du auch direkt die Zeichen zählen und zu einem String aufaddieren und diesen darstellen:

    [autoit]

    Func GetPCWSTR2(ByRef $struct, $sElementName) ; avoids memory access conflicts
    Local $anz = 0 ;anzahl Zeichen
    Local $ptr = DllStructGetPtr($struct, $sElementName) ; ptr
    Do
    $char_struct = DllStructCreate("WCHAR", $ptr + $anz) ; get memory location
    $anz += 1
    Until DllStructGetData($char_struct, 1) = Chr(0) ; end of string
    Local $string_struct = DllStructCreate("WCHAR[" & $anz / 2 & "]", $ptr) ; create struct with correct amount of bytes
    Return DllStructGetData($string_struct, 1)
    EndFunc ;==>GetPCWSTR2

    [/autoit]

    uups, jetzt habe ich das doppelt gemoppelt^^

    EDIT// Ich weiss jetzt nicht, ob du den Pointer direkt aus der struct ausliest (statt des strings), daher könnte auch

    [autoit]

    Local $ptr = ptr(DllStructGetData($struct, $sElementName)) ; ptr

    [/autoit]

    den pointer liefern

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    5 Mal editiert, zuletzt von Andy (29. September 2013 um 10:20)

  • Andy: Ein WCHAR ist 2bytes groß. Sprich um jeden WCHAR eines Strings auszulesen muss man den Pointer auf das erste Zeichen stets um die Größe eines WCHARS erhöhen (= 2).
    Also ungefähr so:
    [0x0] - erster WCHAR
    [0x2] - zweiter WCHAR
    [2*(n-1)] - n-ter WCHAR (0 < n)

    7 Mal editiert, zuletzt von CentuCore (29. September 2013 um 17:43)

  • @CentuCore,

    Zitat

    Ein WCHAR ist 2bytes groß.

    richtig^^
    Da aber ein einzelner WCHAR in einer Struct auch 2 Bytes gross ist, und ich mit $i nur die Zeichen (Anzahl der WCHAR !) zähle, reicht es, wenn ich den Zähler um eins erhöhe. "Intern" erhöht sich der Byte-Zähler um 2, ich möchte aber keine Bytes zählen sondern WORD (WCHAR).
    AutoIt passt das automatisch an, genauso wenn in einer Struct mehrere DWORD (4 Bytes) stehen. Die interne Zählvariable pro DWORD ist dann auch 4 Bytes groß.

    /EDIT/ hast Recht, genau deshalb teile ich durch 2 :thumbup:

  • Zitat

    Da aber ein einzelner WCHAR in einer Struct auch 2 Bytes gross ist, und ich mit $i nur die Zeichen (Anzahl der WCHAR !) zähle, reicht es, wenn ich den Zähler um eins erhöhe. "Intern" erhöht sich der Byte-Zähler um 2, ich möchte aber keine Bytes zählen sondern WORD (WCHAR).


    Es geht aber nicht um die Anzahl der Bytes pro Struktur, sondern um den Zeiger auf den nächsten WCHAR (= Adresse).
    AutoIt passt beim DllStruct erstellen nichts an.
    Stichwort:

    [autoit]


    $char_struct = DllStructCreate("WCHAR", $ptr + $anz) ; get WRONG memory location, if you use $anz += 1!
    $char_struct = DllStructCreate("WCHAR", $ptr + ($anz * 2)) ; get CORRECT memory location, if you use $anz += 1!

    [/autoit]

    3 Mal editiert, zuletzt von CentuCore (1. Oktober 2013 um 19:07)

  • So wie es aussieht ist Andy der Gewinner, dieser Challenge...

    So siehts aus:

    [autoit]

    Func GetPCWSTR(ByRef $struct, $sElementName) ; avoids memory access conflicts
    Local $anz = 0 ;anzahl Zeichen
    Local $ptr = DllStructGetData($struct, $sElementName) ; ptr
    ;~ Local $ptr = ptr(DllStructGetData($struct, $sElementName)) ; klappt auch
    Do
    $char_struct = DllStructCreate("WCHAR", $ptr + $anz) ; get memory location
    $anz += 1
    ConsoleWrite(DllStructGetData($char_struct, 1))
    Until DllStructGetData($char_struct, 1) = Chr(0) ; end of string
    Local $string_struct = DllStructCreate("WCHAR[" & $anz / 2 & "]", $ptr) ; create struct with correct amount of bytes
    Return DllStructGetData($string_struct, 1)
    EndFunc

    [/autoit]

    Zwar gibt es keinen Absturz mehr, dafür endet der Link beim selben Zeichen wie bei der doppelt gemoppelt Lösung:

    Zitat

    h?t?t?p?:?/?/?g?o?.?m?i?c?r?o?s?o?f?t?.?c?o?m?/?f?w?l?i?n?k???L?i?n?k?I?D?=?

    Array Ausgabe:

    Zitat

    So sollte es aussehen:
    http://go.microsoft.com/fwlink?LinkID=1400092

    Habt ihr ne Idee wieso er die letzten 7 Zeichen nicht aufnimmt?


    EDIT: Sorry Leute, ihr habt beide irgendwie Recht, glaube ich...aber bitte nicht drum streiten.
    Wenn ich

    [autoit]

    $anz += 2

    [/autoit]

    statt

    [autoit]

    $anz += 1

    [/autoit]

    verwende, dann bekomme ich den vollen string und die Fragezeichen zw. den Zeichen sind damit auch Geschichte. Ich denke damit ist die Sache gelöst! Vielen Dank Jungs :thumbup:

    Einmal editiert, zuletzt von Trolleule1337 (1. Oktober 2013 um 18:54)

  • @CentuCore, ich sagte ja, du hattest Recht, daher habe ich letztendlich durch 2 geteilt.
    Die Frage ist aber weiterhin, wieso nur bis zum siebtletzten Zeichen gezählt wurde :wacko:
    Das würde heissen, dass an dieser Stelle ein "Nullbyte" sitzt, was aber nicht sein kann.

  • Zitat


    Die Frage ist aber weiterhin, wieso nur bis zum siebtletzten Zeichen gezählt wurde
    Das würde heissen, dass an dieser Stelle ein "Nullbyte" sitzt, was aber nicht sein kann.


    Ich habe das Beispiel mit einem C++ Programm nach gebaut und konnte den Fehler nicht reproduzieren.
    Vermuten würde ich, das AutoIt durch Chr() denkt, dass es zwei Bytes vergleichen soll und wegen dem +1 irgendwo der Lo-Anteil eines Words null ist.

    Zitat

    ich sagte ja, du hattest Recht, daher habe ich letztendlich durch 2 geteilt.


    Trotzdem verstehe ich nicht, warum du nicht $anz mit zwei addieren wolltest, da dies 'richtig' wäre. (Im Anschluss natürlich durch zwei dividieren, weil sonst ein Schmarn heraus kommen würde.)
    Zumal dadurch nur halb soviele Schleifen Durchgänge nötig sind.


    @Trolleule: Könntest du das Ganze mit $anz += 1, sowie ChrW() anstelle von Chr() testen?
    Würde mich interessieren, ob dann immer noch beim siebtletztem Zeichen aufgehört wird.

    3 Mal editiert, zuletzt von CentuCore (2. Oktober 2013 um 02:48)

  • Zitat

    @Trolleule: Könntest du das Ganze mit $anz += 1, sowie ChrW() anstelle von Chr() testen?
    Würde mich interessieren, ob dann immer noch beim siebtletztem Zeichen aufgehört wird.

    So hatte ich es anfangs beim Testen auch...

    Trolleule1337
    WENN ChrW(), dann auch testen auf ChrW(0) !