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?



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


    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


    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)

  • 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 :thumbsup:

  • 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

  • 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 _WinAPI_ReadProcessMemory()
    Aber wenn man das macht, braucht man das ganze DLL-Gedöns nicht^^

  • 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:
    $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)
    ... 
    dann kann ich jedes Byte einzeln auslesen.


    Wenn ich dies aber so umsetze:
    $struct = DllStructCreate("BYTE[8]", $ptr[0])
    $ANTWORT_BYTE1 = DllStructGetData($struct, 1) 
    dann kann ich nur den Wert des gesamten Arrays (8 Bytes) auslesen.


    Meine Vorstellung wäre es, das man mit einem "Trenner"
    $ANTWORT = DllStructGetData($struct, 1.1)
    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.


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


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


    $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


    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...


    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


  • 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!Dim $a[11] ;nullbasiert
    $struct = DllStructCreate("int[10]") ;einsbasiert


    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


    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


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


    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

  • 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:; 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


    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


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


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






    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.

  • 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:



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


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


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


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


    /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???



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


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


    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


    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!