Kommunikation Skripte untereinander

  • Andy:

    Mit der 64Bit "*.dll" hat bestens funktioniert! -> Vielen Dank!

    Zitat

    zu 2, das war ein kurzfristiger "Fehler" von mir, da bei mir der
    Virenscanner gesponnen hat, wenn ich innerhalb der DLL mehr als 6k
    Speicher reserviert habe.

    Ursprünglich stand dort _mem dd 10000 dup 0 ;10 Kb Speicher

    Jetzt alles klar?

    Jetzt ist fast alles klar. Nur noch eine Frage diesbezüglich: Steht das "K" für 1000 oder 1024?


    [autoit]

    $struct = DllStructCreate("char[500];int", $ptr[0])

    [/autoit]

    Welche größe (bit) bzw. welcher Type ist die von dir angelegte Integer Variable?

    Vielen Dank für deine Bemühungen und deine Gedult ;)

    Gruß
    Homer J. S.

    ...wenn die Donuts auch nur halb so gut schmecken wie sie aussehen, dann sehen sie doppelt so gut aus wie sie schmecken...

  • Zitat

    Nur noch eine Frage diesbezüglich: Steht das "K" für 1000 oder 1024?

    Na, wenn ich 1000 Bytes reserviere, dann steht das k wohl für 1000 8o

    Zitat

    Welche größe (bit) bzw. welcher Type ist die von dir angelegte Integer Variable?

    Wenn man sowohl 64bit als auch 32Bit-Scripte schreibt, welche mit DLLCALL() oder Structs usw. arbeitet, sollte man die in der Hilfe zu DllCall() beschriebenen Datentypen nutzen, welche ihre Größe automatisch an die Bitness anpassen

    Zitat von AutoIt Hilfe


    INT_PTR, LONG_PTR, LRESULT, LPARAM
    an integer big enough to hold a pointer when running on x86 or x64 versions
    of AutoIt.

    UINT_PTR, ULONG_PTR, DWORD_PTR, WPARAM
    an unsigned integer big enough to hold a pointer when running on x86 or x64
    versions of AutoIt.


    Ansonsten ist ein INT 32 Bit breit. Im AutoItscript ist das egal, wichtig wirds bei der Übertragung der Daten an eine 64-Bit-Dll bzw. ein 64-Bit-Assemblerprog im Speicher. (AssembleIt und Assembleit2 arbeiten btw. nur mit der 32-Bit-Version, man kann zwar 64Bit-Programme erstellen, muss aber wie im n-Body-Thread gezeigt, per Zwischenschritt mit 32-Bit-Assembleit im 32Bit-Modus von AutoIt den 64Bit-Code assemblieren, und danach in den 64-Bit-Modus von AutoIt umschalten um den 64-Bitcode auch nutzen zu können)

    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

    Einmal editiert, zuletzt von Andy (14. Oktober 2014 um 13:27)

  • Andy:

    Zitat

    Na, wenn ich 1000 Bytes reserviere, dann steht das k wohl für 1000


    ...da hast du wohl recht - Gedankenfehler meinerseits.

    Ich denke nach soviel Vorschlägen und der grandiosen Idee bzw. Umsetzung von Andy, kann ich den Thread als "gelöst" markieren.

    Vielen Dank nochmal an alle!

    Gruß
    Homer J. S.

    ...wenn die Donuts auch nur halb so gut schmecken wie sie aussehen, dann sehen sie doppelt so gut aus wie sie schmecken...

  • jetzt wollen wir Anwendungen sehen :thumbup:

  • jetzt hab ich noch eine Verständnisfrage. ^^

    Gibt es keine andere Möglichkeit RAM zu reservieren aus einer dll heraus, als den zu verwendeten Speicher schon in der dll zu erzeugen und "nur" in den RAM zu kopieren???

    Es muss doch möglich sein mit einem Befehl einen Speicherbereich im RAM zu erzeugen mit einem Pointer.
    Wenn ich jetzt 100MB reservieren wollte, dann wäre ja die dll in Eurem Beispiel auch 100MB groß.
    Das mag ich jetzt nicht glauben ^^

    Gruß

    MfG Schnuffel

    "Sarkasmus ist die niedrigste Form des Witzes, aber die höchste Form der Intelligenz."
    Val McDermid

    ein paar Infos ...

    Wer mehr als "nur" Hilfe benötigt, kann sich gern im Forum "Programmieranfragen" an uns wenden. Wir helfen in allen Fällen, die die Forenregeln zulassen.

    Für schnelle Hilfe benötigen wir ein ! lauffähiges ! Script, dass wir als Demonstration des Problems testen können. Wer von uns erwartet ein Teilscript erstmal lauffähig zu bekommen, der hat
    1. keine wirkliche Not
    2. keinen Respekt vor Menschen die ihm in ihrer Freizeit Ihre Hilfe anbieten
    3. oder ist einfach nur faul und meint wir coden das für ihn

    In solchen Fällen erlaube ich mir, die Anfrage einfach zu ignorieren. ;)

  • Dynamisches reservieren wurde von Make Grafik wie hier beschrieben ( <- da steht ein link!) schon probiert. Leider erfolglos!
    Den RAM in der DLL zu reservieren und von dort aus zu verwenden/benutzen ist ja nicht das Problem, sondern diesen Speicherbereich ANDEREN Programmen zur Verfügung zu stellen.
    Das geht auch, über den auch oben von mir schon demonstrierten Einsatz von

    [autoit]

    _WinAPI_ReadProcessMemory()

    [/autoit]


    Aber wenn man das macht, braucht man das ganze DLL-Gedöns nicht^^

    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

    4 Mal editiert, zuletzt von Andy (15. Oktober 2014 um 21:50)

  • Normalerweise macht man Interprozesscommunication, indem man entweder eine Art Message Queues verwendet, was aber fuer grosse Datenmengen nicht geeignet ist oder man erzeugt memory mapped files oder geteilte memory regions. Dabei hat man freien Zugriff, muss aber selber aufpassen, dass keine Data-Races entstehen. Das ganze ist aber auf Windows ziemlich kompliziert und so richtig verstehe ich die Schritte auch nicht, die dazu noetig sind. Ich habe fuer sowas in C++ immer boost.interprocess verwendet, wobei ich auch wenn eher meistens Threads statt Prozessen nehme.

  • Andy: Ich habe noch eine Frage bezüglich der DLL und Arrays.

    Hier ein Beispiel. Ich habe 8 Byte Kommunikation mit einem anderem Skript.

    Wenn ich das so machen würde:

    [autoit]

    $struct = DllStructCreate("BYTE;BYTE;BYTE;BYTE;BYTE;BYTE;BYTE;BYTE", $ptr[0])
    $ANTWORT_BYTE1 = DllStructGetData($struct, 1)
    $ANTWORT_BYTE2 = DllStructGetData($struct, 2)
    $ANTWORT_BYTE3 = DllStructGetData($struct, 3)
    ...

    [/autoit]


    dann kann ich jedes Byte einzeln auslesen.

    Wenn ich dies aber so umsetze:

    [autoit]

    $struct = DllStructCreate("BYTE[8]", $ptr[0])
    $ANTWORT_BYTE1 = DllStructGetData($struct, 1)

    [/autoit]


    dann kann ich nur den Wert des gesamten Arrays (8 Bytes) auslesen.

    Meine Vorstellung wäre es, das man mit einem "Trenner"

    [autoit]

    $ANTWORT = DllStructGetData($struct, 1.1)

    [/autoit]


    die Array Elemente driekt auslesen kann. Gibt es diese Möglichkeit?

    Mir ist bewußt, das man das ganze Array wieder in seine 8 Bytes zerlegen könnte, aber der direkte Weg spart Verarbeitungszeit. Ich möchte zudem später nicht mit 8 Bytes sondern mit >256 Bytes arbeiten und daher wäre es mit einem Array doch deutlich einfacher.

    Vielen Dank für deine Bemühung.

    Gruß
    Homer J. S.

    ...wenn die Donuts auch nur halb so gut schmecken wie sie aussehen, dann sehen sie doppelt so gut aus wie sie schmecken...

  • Hi,

    eine Struct ist doch nichts weiter als ein Array?!
    Darin kannst du natürlich jedes Element einzeln ansprechen.

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

    $struct = DllStructCreate("BYTE[8]")

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

    for $i=1 to 8
    dllstructsetdata($struct,1,$i*10,$i)
    next

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

    $ANTWORT_BYTE1 = DllStructGetData($struct, 1,1)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ANTWORT_BYTE1 = ' & $ANTWORT_BYTE1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $ANTWORT_BYTE2 = DllStructGetData($struct, 1,2)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ANTWORT_BYTE2 = ' & $ANTWORT_BYTE2 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $ANTWORT_BYTE3 = DllStructGetData($struct, 1,3)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ANTWORT_BYTE3 = ' & $ANTWORT_BYTE3 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $ANTWORT_BYTE4 = DllStructGetData($struct, 1,4)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ANTWORT_BYTE4 = ' & $ANTWORT_BYTE4 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

    [/autoit]

    Das was du suchst, ist der "Index" (s. Hilfe zu DllStructGetData() )

  • Andy: Manchmal sieht man den Wald vor lauter Bäumen nicht ;)
    Habe dein Beispiel zusammen mit der DLL getestet und es funktioniert einwandfrei. Vielen Dank für deine Hilfe!

    Gruß
    Homer J. S.

    ...wenn die Donuts auch nur halb so gut schmecken wie sie aussehen, dann sehen sie doppelt so gut aus wie sie schmecken...

  • Anhand der Pointer kannst du natürlich auch verschiedene Structs an EINER Speicherposition erstellen und somit bestimmte (Teil-) Daten schreiben oder lesen.

    HIER ein Beispiel, wie man so etwas gebrauchen kann, der gesamte Thread ist übrigens lesenswert.

  • Ich finde Andys Methode super und wollte das gerne auf mein Script anwenden.

    Jedoch muss ich nicht nur Werte sondern ganze Arrays übertragen.... Hierzu habe ich versucht die Funktionen von BugFix zu verwenden. Aber ich habe keine Ahnung wie ich in diesen Funktionen die .dll von Andy einbinden kann...

    Spoiler anzeigen
    [autoit]


    $array1 = _GetTestArray(5,2)
    $2D_Struct_str = _ArrayToByteArray2D($array1, 'char[128]')
    $a2 = _ByteArray2DToArray($2D_Struct_str)
    _ArrayDisplay($a2, 'String-Strukt als Array')

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

    ;==================================================================================================
    ; Funktion _GetTestArray($iUbDim1 [, $iUbDim2=0, $sValue='Wert ']])
    ; Beschreibung Gibt ein 1D- oder 2D-Array mit Testdaten zurück
    ; Parameter $iUbDim1 Anzahl Elemente 1. Dimension
    ; optional $iUbDim2 Anzahl Elemente 2. Dimension; wird kein Wert oder Wert < 2 übergeben,
    ; dann wird ein 1D-Array erzeugt; Standard: 0 = 1D-Array
    ; optional $sValue Standard: "Wert $i" bzw. "Wert $i/ $k"; $i bzw $k werden immer angefügt
    ; Autor BugFix ([email='bugfix@autoit.de'][/email])
    ;==================================================================================================
    Func _GetTestArray($iUbDim1, $iUbDim2=0, $sValue='Wert ')
    Local $i, $k, $2ndDim = False
    Local $aOut[$iUbDim1]
    If $iUbDim2 > 1 Then
    $2ndDim = True
    ReDim $aOut[$iUbDim1][$iUbDim2]
    EndIf
    For $i = 0 To $iUbDim1 -1
    If $2ndDim Then
    For $k = 0 To $iUbDim2 -1
    $aOut[$i][$k] = $sValue & $i & '/ ' & $k
    Next
    Else
    $aOut[$i] = $sValue & $i
    EndIf
    Next
    Return $aOut
    EndFunc ;==>_GetTestArray

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _CreateByteArray2D
    ; Description ...: Erstellt die Struktur Bytearray im Zugriffs-Stil eines Array-2D
    ; Syntax.........: _CreateByteArray2D($sType, $iRows, $iCols)
    ; Parameters ....: $sType String zu speichernder Datentyp
    ; $iRows Anzahl Zeilen
    ; $iCols Anzahl Spalten
    ; Return values .: Bytearray-Struktur
    ; Author ........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ; Remarks .......: Zusätzlich zu den Daten werden Größe und Name des verwendeten Datentyps und die Größe der Dimensionen
    ; in der Struktur hinterlegt
    ; ===============================================================================================================================
    Func _CreateByteArray2D($sType, $iRows, $iCols)
    Local $iSize = DllStructGetSize(DllStructCreate($sType, 1))
    Local $aByte = DllStructCreate('byte[' & $iSize *$iRows *$iCols & '];int size;wchar type[128];int ubound[2]')
    DllStructSetData($aByte, 'size', $iSize)
    DllStructSetData($aByte, 'type', $sType)
    DllStructSetData($aByte, 'ubound', $iRows, 1)
    DllStructSetData($aByte, 'ubound', $iCols, 2)
    Return $aByte
    EndFunc ;==>_CreateByteArray2D

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ByteArray2DToArray
    ; Description ...: Überträgt die Daten aus dem Bytearray in ein klassisches 2D-Array
    ; Syntax.........: _ByteArray2DToArray($aByte)
    ; Parameters ....: $aByte die Struktur Bytearray
    ; Return values .: Ein klassisches 2D-Array mit allen Werten aus der Struktur
    ; Author ........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ; ===============================================================================================================================
    Func _ByteArray2DToArray(ByRef $aByte)
    Local $Ub1 = DllStructGetData($aByte, 'ubound', 1)
    Local $Ub2 = DllStructGetData($aByte, 'ubound', 2)
    Local $a[$Ub1][$Ub2]
    Local $sType = DllStructGetData($aByte, 'type')
    Local $iSize = DllStructGetData($aByte, 'size')
    Local $iShiftPtr, $tmpStruct, $p_aByte = DllStructGetPtr($aByte)
    For $i = 0 To $Ub1 -1
    For $j = 0 To $Ub2 -1
    $iShiftPtr = ($i * $Ub2 * $iSize) + ($j * $iSize)
    $tmpStruct = DllStructCreate($sType, $p_aByte +$iShiftPtr)
    $a[$i][$j] = DllStructGetData($tmpStruct, 1)
    Next
    Next
    Return $a
    EndFunc ;==>_ByteArray2DToArray

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ArrayToByteArray2D
    ; Description ...: Überträgt die Daten aus dem Bytearray in ein klassisches 2D-Array
    ; Syntax.........: _ArrayToByteArray2D($array, $sType, $iStart)
    ; Parameters ....: $array klassisches 2D-Array
    ; $sType Datentyp im Array (Standard "int")
    ; $iStart Start-Index (Standard 0)
    ; Return values .: Bytearray-Struktur mit allen Werten aus dem Array
    ; Author ........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ; ===============================================================================================================================
    Func _ArrayToByteArray2D(ByRef $array, $sType="int", $iStart=0)
    If $iStart < 0 Then $iStart = 0
    Local $Ub1 = UBound($array) - $iStart
    Local $Ub2 = UBound($array, 2)
    Local $aByte = _CreateByteArray2D($sType, $Ub1, $Ub2)
    Local $iSize = DllStructGetData($aByte, 'size')
    Local $iShiftPtr, $tmpStruct, $p_aByte = DllStructGetPtr($aByte)
    For $i = $iStart To $Ub1 -1
    For $j = 0 To $Ub2 -1
    $iShiftPtr = (($i - $iStart) * $Ub2 * $iSize) + ($j * $iSize)
    $tmpStruct = DllStructCreate($sType, $p_aByte +$iShiftPtr)
    DllStructSetData($tmpStruct, 1, $array[$i][$j])
    Next
    Next
    Return $aByte
    EndFunc ;==>_ByteArray2DToArray

    [/autoit]

    Kann es evtl. sein, dass die .dll vom Andy dies nicht unterstützt?

  • Also mit einer 1D Array habe ich das schonmal wie folgt geschafft... Wahrscheinlich nicht die sauberste Methode aber sie funktioniert :D

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

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

    $file_dll = @scriptdir & '\SharedMemory.DLL'
    $ptr = DllCall(DllOpen($file_dll), "dword", "GetPointer")
    $struct = DllStructCreate('WCHAR[5000]', $ptr[0])

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

    $array1 = _GetTestArray(100)
    DllStructSetData($struct, 1, _ArrayToString($array1,'|'))

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

    _ArrayDisplay(StringSplit(DllStructGetData($struct, 1), '|', 2))

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

    ;==================================================================================================
    ; Funktion _GetTestArray($iUbDim1 [, $iUbDim2=0, $sValue='Wert ']])
    ; Beschreibung Gibt ein 1D- oder 2D-Array mit Testdaten zurück
    ; Parameter $iUbDim1 Anzahl Elemente 1. Dimension
    ; optional $iUbDim2 Anzahl Elemente 2. Dimension; wird kein Wert oder Wert < 2 übergeben,
    ; dann wird ein 1D-Array erzeugt; Standard: 0 = 1D-Array
    ; optional $sValue Standard: "Wert $i" bzw. "Wert $i/ $k"; $i bzw $k werden immer angefügt
    ; Autor BugFix ([email='bugfix@autoit.de'][/email])
    ;==================================================================================================
    Func _GetTestArray($iUbDim1, $iUbDim2=0, $sValue='Wert ')
    Local $i, $k, $2ndDim = False
    Local $aOut[$iUbDim1]
    If $iUbDim2 > 1 Then
    $2ndDim = True
    ReDim $aOut[$iUbDim1][$iUbDim2]
    EndIf
    For $i = 0 To $iUbDim1 -1
    If $2ndDim Then
    For $k = 0 To $iUbDim2 -1
    $aOut[$i][$k] = $sValue & $i & '/ ' & $k
    Next
    Else
    $aOut[$i] = $sValue & $i
    EndIf
    Next
    Return $aOut
    EndFunc ;==>_GetTestArray

    [/autoit]
  • Es ist völlig egal, in welcher Form die Daten übergeben werden, Hauptsache ist, es werden genügend Bytes reserviert :D
    Und ob man ein 3D oder nD-Array übergibt ist auch unerheblich, bis es 3D-Speicher gibt, dauert es noch etwas. (ok, ne tesafilmrolle wird ja schon als 3d-Speicher beworben)
    Speicher ist grundsätzlich linear angeordnet, also ist das bei Arrays genauso!
    Übrigens kann man sich, wenn man denn weiss was man tut, komplett auf Arrays verzichten! Mit DllStructs sind idR. in höherer Geschwindigkeit identische Funktionen wie bei Verwendung von Arrays machbar.
    Die Umwandlung wie bei rynow kann man sich also sparen^^

  • ???? Wie kann ich eine Array in ein struct setzen?


    Du musst nur definieren, was dein Array als Inhalt hat!

    [autoit]

    Dim $a[11] ;nullbasiert
    $struct = DllStructCreate("int[10]") ;einsbasiert

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

    For $i = 1 To 10
    $wert = Random(1, 100000, 1) ;irgendeinen wert
    $a[$i] = $wert ;wert in array
    DllStructSetData($struct, 1, $wert, $i) ;wert in struct
    Next

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

    For $i = 1 To 10 ;auslesen
    ConsoleWrite("Array = " & $a[$i] & @CRLF);array
    ConsoleWrite("Struct = " & DllStructGetData($struct, 1, $i) & @CRLF)
    ConsoleWrite("Struct = " & _a($i) & @CRLF & @CRLF)
    Next

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

    Func _a($inhalt) ;dllstructgetdata in "kurz" ^^
    Return DllStructGetData($struct, 1, $inhalt)
    EndFunc ;==>_a

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

    Im AutoIt-Array hast du den unschlagbaren Vorteil, verschiedene Datentypen mischen zu können, ohne dich um die ....Datentypen kümmern zu müssen, "variant" sei Dank!
    Allerdings muss man beim Zuweisen bzw. Auslesen sowieso die "richtigen" Datentypen haben, also kann man sie auch direkt in bspw. einer Struct definieren.
    Übrigens ist die "Arrayschreibweise" nichts anderes als ein einfacheres Abbild der Datenstruktur (sic) im Speicher! Intern liegen die Daten sowieso in einem Speicherbereich, ob man den nun Struct, Liste, verkettete Liste oder was auch immer nennt, ist unerheblich.

    /EDIT
    Um das mal deutlicher zu machen, bis auf die blutigsten Anfänger würde es niemandem einfallen, beispielsweise die Pixel in einem Bild in ein Array einzulesen, dann zu bearbeiten und dieses Array dann wieder in Pixel zu übertragen.
    Eine Bitmap IST bereits ein Array, genau wie die Daten in einem WMV-Musikstück, der Text in einem *.au3-Script uswusf

    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

    3 Mal editiert, zuletzt von Andy (31. Oktober 2014 um 22:08)

  • Bei einem 1 Dimensionalen Array ist das ja einfach. Via DllStructCreate gibt es ja die Möglichkeit einen Index anzugeben. Sieht ja in etwa so aus: "int var[100]" (1D Array mit 100 Elementen)

    "Schwieriger" wird es bei n-Dimensionale Array's. Da muss man dann schon ein wenig rechnen, geht aber im Grunde ganz einfach. Du musst wissen welche Dimension wie viele Indizes besitzt. Dann kannst du das Array in ein Eindimensionales umrechnen.

    Bei einem 3D Array sieht das so aus:
    1. Dimension: 200 Elemente
    2. Dimension: 150 Elemente
    3. Dimension: 300 Elemente

    Insgesamt hat das Array dadurch 200*150*300 = 9'000'000 Elemente. Als DllStruct demnach "int var[9000000]" verwenden.
    Um nun auf den Index [55][23][89] zuzugreifen, müssen wir das ein wenig umrechnen.

    Also: 55*150*300 + 23*300 + 89 + 1 = 2'481'990

    (Die +1 in der Formel ist notwendig, da DllStruct mit den Index 1 beginnt)

    Das 2'481'990 Element im 1D Array entspricht also den Indizes [55][23][89] im 3D Array.


    Um nun ein Array als Struct zu konvertieren müssen lediglich alle Elemente nach der Reihe nach durchgegangen werden und diese dementsprechend kopiert werden. Das ist aber sehr zeitaufwendig, daher empfiehlt sich das Array direkt als Struct anzulegen und dann mit der oberen genannten Methode mit den einzelnen Indizes zu rechnen.


    Praktisches Beispiel:

    [autoit]

    ; Array[10][5]
    $tStruct = DllStructCreate('byte d1; byte d2; dword array[50]')
    $tStruct.d1 = 10 ; 1. Dimension -> 10 Elemente
    $tStruct.d2 = 5 ; 2. Dimension -> 5 Elemente

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

    For $i = 0 To $tStruct.d1 -1
    For $n = 0 To $tStruct.d2 -1
    $tStruct.array(($i * $tStruct.d2 + $n +1)) = Random(1, 100, 1) ; Jedes Element zufällig befüllen
    Next
    Next

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

    ; $Array[2][4]
    ConsoleWrite(Pseudo2DArray($tStruct, 2, 4) & @CRLF)

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

    Func Pseudo2DArray(ByRef $t, $x, $y)
    Return $tStruct.array(($x * $t.d2 + $y +1))
    EndFunc

    [/autoit]


    Schwieriger wird es wenn mehrere Datentypen im Array vorhanden sind, da muss sich ein anderes System überlegt werden. Wenn du willst schreibe ich dir Morgen ein paar Funktionen für die Verwaltung von Daten des Datentypes Variant (speziell ausgelegt für n-Dimensionale Arrays). Dann musst du zwar Umwege über Funktionen machen, sollte aber relativ "einfach" sein damit zu arbeiten.

    Einmal editiert, zuletzt von Yjuq (31. Oktober 2014 um 22:43)

  • So schön wie MakeGrafik das erklärt hat, macht das übrigens auch jeder Compiler.
    Ins Eingemachte geht es dann, wenn man sich Gedanken über Array of Structs (AoS) oder einer Struct of Arrays (SoA) macht. Mit dem, was MakeGrafik erklärt hat, wird hoffentlich klar, dass es bei Speicherzugriffen eben NICHT völlig unerheblich ist, ob die Daten direkt hintereinander im Speicher liegen (und somit über den Prozessorcache x-mal schneller gelesen werden können) oder über den "falschen" Index angesprochen, völlig verteilt im Speicher liegen (Cachemisses/Cachepollution bei jedem Zugriff)
    Bei diversen Programmen, welche intensiv mit gespeicherten Daten arbeiten (Datenbanken) wurde schon Faktor 2.5 bis 3 an Beschleunigung erreicht, NUR weil von AoS auf SOA umgestellt wurde, also aus einem Array[x][y] ein Array[y][x] gemacht wurde!

  • Guten Morgen zusammen,

    vielen Dank für eure Erklärungen. Andys 1D Array kann ich noch voll und ganz nachvollziehen. Jedoch das 3D Array von Make-Grafik ist doch sehr kompliziert für mich :). z. B. versteh ich überhaupt nicht wie ich durch dieses Beispeil ein 2D Struct Array erstelle.

    @Andy hast du evtl. ein Beispiel wie ich ein SOA erstelle?

    aaaa. Nach 30sten durchlesen, die Berechnung verstanden :party:

    indem Fall würde mein 1D array (nach Make-Grafiks) Beispiel wie folgt ausschauen:

    [autoit]


    ; Array[10]
    $tStruct = DllStructCreate('byte d1; dword array[50]')
    $tStruct.d1 = 10 ; 10 Elemente

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

    For $i = 0 To $tStruct.d1 -1
    $tStruct.array(($i +1)) = Random(1, 100, 1) ; Jedes Element zufällig befüllen
    Next

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

    ; $Array[2]
    ConsoleWrite(Pseudo2DArray($tStruct, 2) & @CRLF)

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

    Func Pseudo2DArray(ByRef $t, $x)
    Return $tStruct.array(($x +1))
    EndFunc

    [/autoit]

    /EDIT --

    Ich habe nun versucht eine Funktion daraus zu erstellen um mir das Leben leichter zu machen :). Jedoch habe ich nun das Problem, dass mir die Ausgabe nur den ersten Buchstaben liefert???

    [autoit]


    $tStruct = DllStructCreate('byte d1; byte d2; char array[128]')
    $tStruct.d1 = 10 ; 1. Dimension -> 10 Elemente
    $tStruct.d2 = 5 ; 2. Dimension -> 5 Elemente

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

    _set_2D_struct($tStruct, 2, 2, 'Hallo AutoIt', 'set')
    ConsoleWrite(_set_2D_struct($tStruct,2,2))

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

    func _set_2D_struct(ByRef $t, $x, $y, $value = '', $action = 'get')
    Switch $action
    Case 'get'
    Return $tStruct.array(($x * $t.d2 + $y +1))
    Case 'set'
    $tStruct.array(($x * $t.d2 + $y +1)) = $value
    EndSwitch
    endfunc

    [/autoit]

    Ausgabe: H

  • Andy hast du evtl. ein Beispiel wie ich ein SOA erstelle?

    Ein einfaches Beispiel ist eine Bitmap.
    Jedes einzelne Pixel besteht aus den 4 Kanälen (Bytes) Alpha, Rot,Grün, Blau, also ARGB als DWORD (4 mal 8 Bit)
    Im Speicher stehen die Pixel byteweise nacheinander ARGBARGBARGBARGBARGB... bezeichnet als ein Array of Structures.
    Möchte man nun bspw. 64 rote Farbanteile (64 Bytes passen genau in eine Cacheline) aus dem Speicher lesen und verarbeiten, müssen nun 4x64 Bytes, also 4 Lines im Prozessorcache, gefüllt werden! Drei viertel der Daten im Prozessorcache wären also unnötiger Müll (Cache pollution)!

    Um jetzt die einzelnen Farbkanäle anzusprechen also beispielsweise nur die roten Farbbestandteile, könnte man alle diese Bytes nacheinander in den Speicher schreiben, also als
    AAAAAAAAAA...RRRRRRRRRRRRRRRR...GGGGGGGGGGGGGG...BBBBBBBBBBBBB....Structure of Arrays
    Würde man jetzt 64 rote Farbanteile lesen bzw. bearbeiten wollen, würde der Prozessor mit einem Lesebefehl nur EINE Cacheline füllen müssen!

    Gerade bei der Verarbeitung mit den SSE-Befehlen, also SIMD (Single Instruction Multiple Data), sollte man also tunlichst die Daten entsprechend vorbereiten, damit diese Prozessorbefehle überhaupt ihre Geschwindigkeit ausspielen können!
    Mittlerweile "optimiert" bspw. der INTEL-Compiler schon den C(++)-Code VOR dem Compilieren, um dem Prozessor die "richtige" Reihenfolge der Daten im Speicher zur Verfügung zu stellen. U.a. dadurch wird der Geschwindigkeitsunterschied der compilierten Programme zu anderen Compilern erreicht. 8o
    Btw. kann man über die Shuffle-Befehle die Daten umorganisieren, aber wenn man sich diese "teuren" Befehle sparen kann, um so besser. Eukalyptus hat dazu ein schönes Script geschrieben!

    Wie man schon erahnen kann, hilft einem das o.g. in einem AutoIt-Script geschwindigkeitsmäßig nicht sonderlich viel, dazu ist der Overhead des Interpreters viel zu groß.
    Allerdings schadet es auch nicht. Sollte man bspw. für eine schnelle Berechnung eine Dll, bspw. per C(++) oder Freebasic oder einem beliebigen anderen Compiler erstellen wollen und diese dann mit AutoIt verwenden, wird sich mit Sicherheit die "richtige" Organisation der Daten im Speicher bemerkbar machen!