Einbinden DLL für das Einlesen von Messwerten über die serielle Schnittstelle

  • Hallo Zusammen,

    für ein Projekt muß ich eine DLL der Fa. Steinwald in ein Programm einbinden um über die serielle Schnittstelle Messdaten einlesen zu können. Zu diesem Zweck habe ich eine Doku über die Funktionen in der DLL erhalten zusammen mit Beispielaufrufen aus VB-Programmen. Auch werden in der Doku die Parameter für die einzelnen Funktionen erklärt.

    Hier einmal ein Beispiel:

    pasted-from-clipboard.png

    Der VB-Code hierzu:

    Code
    Declare Function HINET_Get Lib "DCH_32.DLL" (ByVal Typ As Long, ByVal Chan As Long, ByRef Messwert As Double, ByVal fWait As Long) As Long

    Mir fehlt hier jetzt allerdings einfach der Anfang für das Umsetzen der VB-Codes in AutoIt. Kann mir hier bitte von euch jemand einen Tipp geben wie man die DLL "öffnet" und dann die Funktionen darin aufruft (anhand des HINET_GET)?

    Leider kann ich die DLL hier nicht mit posten, da es sich um ein kommerzielles Produkt der Fa. Steinwald handelt. :(

    Besten Dank vorab,

    viele Grüße

    TheDude

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]

    • Offizieller Beitrag

    Ich würde das so angehen, basierend auf der Beschreibung. ich habe nur geändert, dass die Funktion den Messwert zurückgibt, statt ihn ByRef auszulesen. Das passiert nur innerhalb der Funktion beim DllCall so.

    Schau dir mal mein DLL-Tut (in meiner Signatur) an. Da habe ich noch ein paar Bsp.


    EDIT:

    Ich habe mal die Überlegungen aus den nachfolgenden Posts zusammengefasst. Probier aus, was funktioniert.

  • Laut der Beschreibung wird dort als boolean ein 32 Bit-Integer verwendet - oder?

    Dann würde ja der Rückgabewert und der 4. Parameter nicht passen da boolean in DLLCall ein 8 Bit-Wert darstellt.

    Ich denke daher dass man für den Rückgabewert und den 4. Parameter daher stattdessen INT verwenden sollte.

    Und zu dem 3. Parameter: Kann mich irren aber spontan hätte ich Double* statt Double verwendet.

    • Offizieller Beitrag

    Laut der Beschreibung wird dort als boolean ein 32 Bit-Integer verwendet - oder?

    Dann würde ja der Rückgabewert und der 4. Parameter nicht passen da boolean in DLLCall ein 8 Bit-Wert darstellt.

    Ich denke daher dass man für den Rückgabewert und den 4. Parameter daher stattdessen INT verwenden sollte.

    Oops, hast natürlich recht - ich wollte eigentlich "BOOL" verwenden, also den 32 Bit Typ.

    Und zu dem 3. Parameter: Kann mich irren aber spontan hätte ich Double* statt Double verwendet.

    Das ist immer recht fraglich. Mal reicht tatsächlich die vordefinierte Variable, mal muss sie als Pointer übergeben werden. Das sind dann die Dinge, die mit Trial&Error erledigt werden. ;)

  • Das ist immer recht fraglich. Mal reicht tatsächlich die vordefinierte Variable, mal muss sie als Pointer übergeben werden. Das sind dann die Dinge, die mit Trial&Error erledigt werden.

    Hehe - exakt deswegen habe ich es so vorsichtig formuliert.
    Eh ich mir lange dazu den Kopf zerbrochen hätte, hätte ich es einfach mal getestet.
    Geht hier nur leider nicht.


    TheDude - lass dir mal testweise $aRet per _ArrayDisplay() ausgeben. So kannst du herausfinden ob dein gesuchter Wert dann in $aRet[3] steht.

    Oops, hast natürlich recht - ich wollte eigentlich "BOOL" verwenden, also den 32 Bit Typ.

    Ach guck an - hatte ich auch nicht mehr auf dem Schirm dass es da einen ähnlich benannten Typ als 32 Bit-Variante gibt.

  • Hallo ihr Beiden,

    ... vielen Dank für eure Hilfe. Ich werde das die Tage austesten und melde mich dann zurück, ob es funktioniert wie gedacht.

    Das DLL-Tutorial kannte ich gar nicht - finde ich klasse! Besten Dank auch dafür!

    Viele Grüße

    TheDude

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]

  • ... eine Verständnisfrage hätte ich noch, bitte: Man kann die DLL ja mit DLLOpen öffnen und dann mit einem Handle arbeiten oder aber den Namen der DLL bei jedem Aufruf der Funktion als Parameter mitgeben. Was wäre hier die bessere Methode, bzw. wo sind hier die Vor- und Nachteile?

    Nochmals vielen Dank,

    viele Grüße

    TheDude

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]

  • Wenn du mit dem Handle arbeitest, dann wird die DLL einmal geöffnet (mit DLLOpen) und später von dir einmal geschlossen (DLLClose).

    Gibst du nur den Dateipfad der DLL an, so wird ausnahmslos bei jedem DLLCall, der mit der Pfadangabe arbeitet, die DLL geöffnet und geschlossen.

    Das kann bei mehreren hundert/tausend DLL-Aufrufen ziemlich CPU/HDD belastend sein und die Performanz des Skriptes beeinflussen, da bei jedem Aufruf die DLL geöffet+geschlossen werden muss.

    Eventuell kann es noch sein, dass beim DLLOpen das FileHandle gesperrt wird und man die Datei nicht löschen kann, bei DLLCall wäre das dann nur während des Calls.

    Da man im Normalfall aber nicht mehrere tausend Male die Sekunde eine DLL aufruft (ein Fall wäre z.B. _IsPressed mit der user32.dll), kann man ruhig die Pfadangabe verwenden.

  • Es gibt auch DLL's, die z.B. über eine Registrierungsfunktion verfügen, wo man also eine Seriennummer übergeben muss (könnte ich mir auch bei dieser DLL vorstellen). Damit das funktioniert, muss immer die DLL zuerst geöffnet werden, und dann mit dem Handle weitergearbeitet werden. Das ist also immer die sicherere Variante.

  • Hallo Zusammen,

    nochmals vielen Dank für eure Hilfe und die Tipps.

    Ich stehe jetzt am Anfang der Programmierung der Schnittstelle und habe gleich zu Beginn das Problem, dass ich das erste INIT nicht hinbekomme. Nachfolgendes sagt die Doku dazu:

    pasted-from-clipboard.png

    Ich habe jetzt nachfolgendes probiert, bekomme aber stets den Wert 0 (=Fehler) zurück:

    Code
    Dim $ComSettings = "COM1:9600,n,8,1" & Chr(0)
    Dim $Return = DllCall($hDLL,'long','HINET_Init2','string',$ComSettings)
    MsgBox(0,"",$Return)

    In der Doku steht zum Aufruf der Funktion "HINET_Init2" aus VB heraus folgendes:

    Zitat

    Declare Function HINET_Init2 Lib "DCH_32.DLL" (ByVal szInit As String) As Long

    Kann es sein, dass ich den Wert 'string' im DllCall anders schreiben muss?

    [Edit]

    ... wer lesen kann (im DLL-Tutorial) ist klar im Vorteil: nicht 'string' muss es heißen, sondern 'str'. :Face:

    Dennoch bekomme ich da nichts brauchbares zurück außer einem leeren String (müsste aber eine 5 drin stehen). ;( Hat jemand von euch vielleicht eine rettende Idee?

    [Edit]

    Vorab vielen Dank für eure Hilfe,

    viele Grüße

    TheDude

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]

    Einmal editiert, zuletzt von TheDude (4. Dezember 2017 um 18:32)

  • ... OK. Also ich verstehe das nicht so richtig, aber ich bekomme jetzt meinen Wert. Die Rückgabe ist jedoch ein Array: 8|

    Code
    Global $SteinwaldDllHdl = DllOpen(@ScriptDir & "\Steinwald.DLL")
    Global $ComSettings = "COM1:9600,n,8,1" ; Chr(0)
    Global $Wert = DllCall($SteinwaldDllHdl,'long','HINET_Init2','str',$ComSettings) ; mit str* und 0-terminiertem String klappt es übrigens nicht
    ;UBound($Wert) ; = 2
    ;$Wert[0] = Anzahl der Kanäle
    ;$Wert[1] = Inhalt von $ComSettings (COM1:9600,n,8,1)
    DllClose($SteinwaldDllHdl)


    Aber - warum ist das so?

    Viele Grüße

    TheDude

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]

  • ... ok, wieder einmal: Wer lesen kann, ist klar im Vorteil. Sorry! :Face:

    Danke Dir! :thumbup:

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]

  • ... OK, im Grunde habe ich das Thema jetzt verstanden und es klappt auch alles soweit.

    Allerdings habe ich noch ein kleines Problem bei der eingangs erwähnten Funktion HINET_Get. Mit dem dritten Parameter übergebe ich eine Variable vom Typ double an die DLL. Diese Variable muss allerdings als Referenz ('double*') übergeben werden, andernfalls stürzt das Programm sofort ab.

    Ich verwende hierfür jetzt folgendes:

    Code
    $aReturnValue = DllCall($SteinwaldDllHdl, 'boolean', 'HINET_Get', 'long', 0, 'long', 5, 'double*', $DeviceValue, 'boolean', False)

    In $DeviceValue steht nun aber leider stets eine '0', in $aReturnValue[0] eine '1' und in $aReturnValue[1] eine '0'. Im Grunde sagt mir das, dass der Aufruf der Funktion in der DLL soweit korrekt war. Aber einen Wert bekomme ich nicht geliefert. Oder muss ich noch irgendetwas mit der Variablen $DeviceValue "machen" um an den tatsächlichen Wert zu kommen?

    Es gibt auch noch eine andere Funktion, die den Messwert in einen String anstatt einem Double schreibt:

    Code
    $aReturnValue = DllCall($SteinwaldDllHdl, 'boolean', 'HINET_Get3', 'long', 0, 'long', 5, 'str', $DeviceValue, 'boolean', 0)

    Als Rückgabewert in $aReturnValue[0] bekomme ich eine '5', was laut Dokumentation der Funktion HINET_Get3 bedeutet, dass 5 Zeichen in die Variable $DeviceValue geschrieben wurde. Lasse ich mir den Inhalt von $DeviceValue aber z. B. mit MsgBox(0, "", $DeviceValue) anzeigen, dann steht dort drin nur wieder eine '0' ...

    Doku zu HINET_Get3:

    pasted-from-clipboard.png

    Sorry, wenn ich mit dem Thema nerven sollte ...

    Nochmals vielen Dank,

    viele Grüße

    TheDude

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]

  • Hi,

    Diese Variable muss allerdings als Referenz ('double*') übergeben werden, andernfalls stürzt das Programm sofort ab.

    Die "Referenz" ist die Adresse der Variablen.

    Erstelle mit $struct=dllstructcreate("double") einen Platzhalter im Speicher, schreibe dort per dllstructsetdata() deinen Wert hinein und hole dir die Adresse per dllstructgetptr(). Diese übergibst du an deine Funktion.

  • In $DeviceValue steht nun aber leider stets eine '0', in $aReturnValue[0] eine '1' und in $aReturnValue[1] eine '0'. Im Grunde sagt mir das, dass der Aufruf der Funktion in der DLL soweit korrekt war. Aber einen Wert bekomme ich nicht geliefert. Oder muss ich noch irgendetwas mit der Variablen $DeviceValue "machen" um an den tatsächlichen Wert zu kommen?

    Sollte eigentlich in $aReturnValue[3] stehen - da mal nachgesehen?

  • ... oh ... ja, AspirinJunkie, das steht der Wert. :Face:

    Danke Dir!

    Andy: Mit den Structs beschäftige ich mich, wenn das Projekt soweit fertig ist. Ist auf jeden Fall interessant und ich denke, dass ich mir damit das Leben auch ein stückweit einfacher machen kann.

    Nochmals vielen Dank an euch für eure Tipps und eure Geduld. :thumbup:

    Viele Grße

    TheDude

    Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare.
    [Cicero, Philippica 12,2]