Daten aus Pointer in Nim Datentyp einlesen

    • Offizieller Beitrag

    Ich spiele gerade mit der Möglichkeit Daten mittels Dll-Aufruf von AutoIt an Nim zu leiten.

    In pur AutoIt würde ich das so machen, um Strings zu übertragen:

    Nun ist die Frage, wie kann ich in Nim die Daten aus dem Pointer in eine Variable entpacken? Ich erstelle dazu den passenden Datentyp ByteArray, der so dimensioniert ist, dass er exakt die Daten aus dem Pointer aufnehmen kann - aber wie gehts?

    Code
    type ByteArray = array[3*128,char] 
    
    proc sendData(pData: PInt32): int {.stdcall,exportc,dynlib.} =
        var received: ByteArray
        # wie Daten aus Pointer in die Variable entpacken?
    • Offizieller Beitrag

    Ich habe mal ein einfacheres Beispiel erstellt:

    In AutoIt erstellen wir ein Array mit 8 Bytewerten:

    AutoIt
    #AutoIt3Wrapper_UseX64=y
    
    Global $tData = DllStructCreate('byte[8]')
    Global $pData = DllStructGetPtr($tData)
    For $i = 0 To 7
        DllStructSetData($tData, '', $i, $i + 1)
    Next
    
    Global $aRet = DllCall('test.dll', 'int', 'sendData', 'ptr', $pData)
    ConsoleWrite($aRet[0] & @CR)

    Der Pointer wird an die Dll in Nim gesendet.

    In Nim bekommen wir den Pointer und erstellen damit ebenfalls ein Array mit 8 Werten:

    Code
    proc sendData(pData: ptr array[8, byte]): int {.stdcall,exportc,dynlib.} =
        var received: ptr array[8, byte]
        received = pData
        for i in 0..7:
          result += int(received[i])

    Zum testen addiere ich die übergebenen Werte und sende sie an AutoIt zurück, damit man das korrekte Ergebnis sehen kann.

    • Offizieller Beitrag

    Um das Ganze noch flexibler zu machen, kann man auch den Pointer und die Anzahl der Bytes übergeben:

    In Nim dann ein Pointer auf ein "UncheckedArray" verwenden:

    Code
    proc sendData(pData: ptr UncheckedArray[byte], iCount: int): int {.stdcall,exportc,dynlib.} =
        for i in 0..iCount - 1:
          result += int(pData[i])
        pData[iCount - 1] = 0 # den letzten Wert auf 0 setzen (als Test)
    • Offizieller Beitrag

    Danke, numerische Werte klappen tadellos.

    Jetzt wollte ich Strings übergeben. Strings aus AutoIt sind in Nim cstring. Und da fängt die Misere an. Versuche ich auf string zu casten crasht es. Und auf cstring kann ich nicht mit Range im Index zugreifen. Meine Idee war, Strings zusammenzuhängen und die Länge der Einzelstrings parallel als Array. Dann kann man das hinterher wieder zerlegen.

    Die DLL

    • Offizieller Beitrag

    Wenn Du Strings übergeben willst, pack sie am besten in eine Struktur (mit Nullbyte am Ende) und übergib nur die Pointer auf die Strings:

    Und in Nim:

    Code
    proc sendData(pData: ptr UncheckedArray[cstring], iCount: int): int {.stdcall,exportc,dynlib.} =
      var sData: cstring
      for i in 0..iCount - 1:
        sData = pData[i]
        result += sData.len

    Damit man den Erfolg sieht, lasse ich in Nim die Stringlängen addieren und an AutoIt zurückgeben.

    • Offizieller Beitrag

    Wenn Du Strings übergeben willst, pack sie am besten in eine Struktur (mit Nullbyte am Ende) und übergib nur die Pointer auf die Strings

    :thumbup: Fein, wieder einen Schritt weiter.

    Und jetzt kommt gleich der nächste Punkt, wo ich hänge.

    Das bisherige diente dazu um 1..n Dateipfade übergeben zu können. Jetzt verarbeite ich die entsprechenden Dateien mit Nim und will das Ergebnis sofort zurückliefern. Nur weiß ich nicht, wie ich die Datenstruktur zum Empfang des Ergebnisses bereits beim Aufruf übergeben soll, wenn die Anzahl/Länge der Elemente erst zur Laufzeit bestimmt wird (z.B. Variablennamen auslesen o.ä.). Möglich wäre als Return Type cstring zu verwenden mit Trennzeichen zwischen den Werten und in AutoIt durch Splitten in ein Array packen. Halte ich aber für die schlechtere Variante, als wenn ich es in einer Struktur habe, auf die ich sofort ohne Umwandlung zugreifen kann.

    Bei Anwendung von Dll hat man ja oft den Hinweis: "Rufe zuerst mit NULL für den Parameter auf, um die Größe für den Puffer zu erhalten" - Das mag gehen, wenn ich einen Fenstertitel abfrage. Aber ich kann doch nicht 2-mal komplexe Programmabläufe durchführen um beim ersten mal nur die Größe zu erhalten. :rolleyes:

    Bin für Ideen empfänglich. ;)

    • Offizieller Beitrag

    Das bisherige diente dazu um 1..n Dateipfade übergeben zu können. Jetzt verarbeite ich die entsprechenden Dateien mit Nim und will das Ergebnis sofort zurückliefern.

    Was willst Du denn verarbeiten?

    Für die Strings (Dateipfade) hast Du doch schon die Pointer übergeben. Die Strings kannst Du somit in Nim ändern und dann mit AutoIt (DllStructGetData) auslesen.

    Da musst Du nichts extra zurückgeben.

    • Offizieller Beitrag

    Ich übergebe Dateipfade, lese mit Nim die Dateien ein, parse Includes, Variablen, Konstanten, Funktionen und will all diese Daten zurückgeben. Menge ist vorher unbekannt.

    Soll das Grundgerüst werden für mein ManageIncludes und die Überarbeitung von UnusedVars.

  • Um das Ganze noch flexibler zu machen, kann man auch den Pointer und die Anzahl der Bytes übergeben:

    Die Anzahl der Bytes kannst du mit .sizeof ermitteln.

    Code
    # Compile x64: nim c -d:release -o:transfer.dll transfer.nim
    # Compile x86: nim c --cpu:i386 -d:release -o:transfer32.dll transfer.nim
    
    # * x64: Call sendData
    # * x86: Call sendData@4
    proc sendData(pData: ptr UncheckedArray[byte]): int {.stdcall,exportc,dynlib.} =
        var iCount: int = pData.sizeof
        for i in 0..iCount - 1:
          result += int(pData[i])
        pData[iCount - 1] = 0 # den letzten Wert auf 0 setzen (als Test)
    • Offizieller Beitrag

    Ich übergebe Dateipfade, lese mit Nim die Dateien ein, parse Includes, Variablen, Konstanten, Funktionen und will all diese Daten zurückgeben. Menge ist vorher unbekannt.

    Ah ok! Das ist ein Problem!

    Ich würde trotzdem von AutoIt aus den Speicher reservieren (DllStructCreate).

    Einfach eine geschätzte Maximalgröße eintragen, den Pointer darauf an Nim übergeben, dort die Änderungen vornehmen und dann (je nach Datenstruktur) ein Int für die Anzahl an AutoIt zurückgeben.

    • Offizieller Beitrag

    Ich würde trotzdem von AutoIt aus den Speicher reservieren (DllStructCreate).

    Einfach eine geschätzte Maximalgröße eintragen, den Pointer darauf an Nim übergeben, dort die Änderungen vornehmen und dann (je nach Datenstruktur) ein Int für die Anzahl an AutoIt zurückgeben

    Ja, ist wohl die sinnvollste Variante.

    Wobei ich mich gerade frage, warum ich das nach Autoit zurückgeben will. Die Projekte kann ich doch kpl. in Nim umsetzen. :Face:

    Aber Datenaustausch kann man immer brauchen. Danke nochmal für die "Erleuchtung" :D

  • BugFix 1. Juni 2020 um 14:34

    Hat den Titel des Themas von „[offen] Daten aus Pointer in Nim Datentyp einlesen“ zu „Daten aus Pointer in Nim Datentyp einlesen“ geändert.
    • Offizieller Beitrag

    Ich greif das noch mal kurz auf, da ich etwas gebraucht habe, um verschachtelte Pointer aufzulösen (wenn man weiß, wie es geht, ist es natürlich einfach :whistling:).

    Hier mal ein einfaches Bsp.: