Problem mit DllCall (aaeonEAPI.dll)

  • Hallo Zusammen,

    ich benötige nach langer Zeit nochmals eure Hilfe. Ich möchte von meinem Mainboard Informationen (Temperatur, GPIO, usw...) abrufen bzw. setzen. Allerdings komme ich mit der DLL nicht wirklich weiter. Nach der Dokumentation (pdf im Anhang) muss man erst ein "EApiLibInitialize" ausführen um gewisse andere Funktionen ausführen zu können und dies funktioniert schon mal ohne Fehlermeldung. Nach Beendigung des Programms muss man ein "EApiLibUnInitialize" ausführen was auch ohne Fehlermeldung funktioniert. Allerdings wenn ich eine andere Funktion aufrufe, dann schließt sich das Script ohne Fehlermeldung oder sonstiges. Ich muss zugeben, dass ich mit DLL´s nicht wirklich bewandert bin. Daher bitte ich euch, mir unter die Arme zu greifen und somit zu helfen.

    Enthaltene Dateien im Anhang (Zip-File):

    1 - aaeonEAPI.dll
    2 - aaeonEAPI.h
    3 - aaeonEAPI.lib
    4 - aaeonEAPI.pdf


    Mein Testcode:

    Spoiler anzeigen

    Ich bedanke mich im voraus für eure Unterstützung/Hilfe!


    Gruß

    Homer J. S.

  • Homer J. S. 20. März 2019 um 23:37

    Hat den Titel des Themas von „DllCall aaeonEAPI.dll“ zu „Problem mit DllCall (aaeonEAPI.dll)“ geändert.
  • Code
    EApiStatus_t EAPI_CALLTYPE EApiBoardGetValue (__IN EApiId_t Id, __OUT uint32_t * pValue)

    Deine DllCalls sind grundsätzlich falsch, "none" darfst du als Returnwert nicht nehmen wenn in dem Handbuch explizit EApiStatus_t (das ist uint32_t getypedefed) verlangt wird. Also musst du das schon mal ändern.

    Dazu kommt, dass du eine illegalen Pointer (Nullpointer) als pValue Parameter nimmst. Hier musst du ein neues DllStruct mit dem Element erstellen das gefordert ist, also uint, davon den Pointer holen mittels DllStructGetPtr, und nachdem du das gemacht hast, diesen Parameter als "uint_ptr" (oder "uint*" - AutoIt wandelt das um) an den DllCall übergeben.

    Als Returnwert der Funktion kriegst du nur einen Statuscode der beinhaltet ob die Operation erfolgreich war, der Wert steht im dereferenzierten Pointer bzw. im Struct wenn du ihn direkt ausliest.

    Nicht zu vergessen ist CallType der Funktion, es handelt sich hierbei um keinen Standardcall sondern um einen API Call, das kannst du in AutoIt mit :cdeclhinter dem Returntype machen.

    Nachdem ich weiteres Material zusammengesucht habe (was die Returncodes betrifft, die tauchen nämlich nirgends auf) habe ich folgendes zum laufen bekommen.

    Dein Call kann also so oder so nicht funktionieren.

    Code
    $Buffer=0
    $EAPI_ID_HWMON_CPU_TEMP=0x20000 ;Aus der Datei aaeonEAPI.h
    $aRet=DllCall($hDLL, "uint", "EApiBoardGetValue", "uint", $EAPI_ID_HWMON_CPU_TEMP, "uint*", $Buffer)

    Hättest du ihn so formuliert, ginge es:

    Code
    $Buffer=DllStructCreate("uint")
    $pBuffer = DllStructGetPtr($Buffer, 1)
    $EAPI_ID_HWMON_CPU_TEMP=0x20000 ;Aus der Datei aaeonEAPI.h
    $aRet=DllCall($hDLL, "uint:cdecl", "EApiBoardGetValue", "uint", $EAPI_ID_HWMON_CPU_TEMP, "uint_ptr", $pBuffer)

    Dieser Code crasht bei mir nicht, gibt aber als pValue 0 und EAPI_STATUS_ERROR zurück. Vielleicht habe ich auch die Hardware dafür nicht, keine Ahnung. Probier mal obs bei dir klappt.

    Den Code habe ich nicht gesäubert, und er sieht ehrlich gesagt ziemlich beschissen aus, du solltest ihn sauberer schreiben.

  • Ich hab mir mal die Freiheit genommen und dein Skript angepasst, ich kriege bereits für das Initialize einen Returnwert von Not_Initialized.

    Wie gesagt: Probier es mal auf deiner Maschine aus, vielleicht fehlt mir ja die Software oder was anderes dazu.

    Die Daten kannst du auch über andere Wege auslesen, statt über eine DLL, wenn es deinen Standard-PC betrifft. Es gibt auch viele Beispiele in AutoIt, einfach mal danach suchen.

  • alpines:

    Vielen Dank für deine Unterstützung - Dein Code funktioniert einwandfrei :party:

    Jetzt verstehe ich ein wenig mehr, was die Kommunikation mit DLL´s angeht. Somit habe ich mich auch an das Auslesen der Boardinformationen gemacht. Dies funktioniert auch schon, allerdings ändert die DLL die Bufferlänge nicht. Laut Dokumentation ist das eine “__INOUT“ Funktion und daher habe ich “by reference“ angegeben, aber die Bufferlänge bleibt bei meiner Vorgabe. Vieleicht hast du ja noch einen Tipp für mich?

    Ausschnitt aus meinem Code:



    Den Code habe ich nicht gesäubert, und er sieht ehrlich gesagt ziemlich beschissen aus, du solltest ihn sauberer schreiben.

    Das dieser nicht wunderschön ist, das war/ist mir bewusst. Ich teste am Anfang immer ein wenig rum und dann wird es ins reine geschrieben. Zudem wollte ich später wahrscheinlich eine UDF daraus machen.


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

  • Somit habe ich mich auch an das Auslesen der Boardinformationen gemacht. Dies funktioniert auch schon, allerdings ändert die DLL die Bufferlänge nicht. Laut Dokumentation ist das eine “__INOUT“ Funktion und daher habe ich “by reference“ angegeben, aber die Bufferlänge bleibt bei meiner Vorgabe. Vieleicht hast du ja noch einen Tipp für mich?

    Ich nehme mal an, dass der Platz im Buffer reicht und er deswegen die Länge gleichbehält.

    Er sollte einen Fehler zurückgeben wenn er zu klein ist, siehe in der Doku: Returns EAPI_STATUS_MORE_DATA: strlen(Id)+1>*pBufLen

    Vielleicht passt er auch die Buffergröße an, übergib mal einen sehr kleinen Buffer und schau dir an was er zurückgibt und was in *pBuffer und *pBufferLen drinsteht.

  • Vielleicht passt er auch die Buffergröße an, übergib mal einen sehr kleinen Buffer und schau dir an was er zurückgibt und was in *pBuffer und *pBufferLen drinsteht.

    Ich habe mal folgendes getestet:

    Test 1:

    Buffer= char[20]

    Buflen = 1 (Vorbelegung)

    Rückgabewert Buffer = String mit 5 Zeichen (müssen 5 Zeichen sein)

    Rückgabewert Buflen = 1

    => Kein Fehler wird zurückgegeben ($EAPI_STATUS_SUCCESS=0)

    Test 2:

    Buffer= char[1]

    Buflen = 20 (Vorbelegung)

    Rückgabewert Buffer = String mit 1 Zeichen (müssten 5 Zeichen sein)

    Rückgabewert Buflen = 20

    => Kein Fehler wird zurückgegeben ($EAPI_STATUS_SUCCESS=0)

    Test 3:

    Buffer= char[1]

    Buflen = 1 (Vorbelegung)

    Rückgabewert Buffer = String mit 1 Zeichen (müssten 5 Zeichen sein)

    Rückgabewert Buflen = 1

    => Kein Fehler wird zurückgegeben ($EAPI_STATUS_SUCCESS=0)

    Test 4:

    Buffer= char[1]

    Buflen = / (Keine Vorbelegung)

    Rückgabewert Buffer = String mit 1 Zeichen (müssten 5 Zeichen sein)

    Rückgabewert Buflen = 0

    => Kein Fehler wird zurückgegeben ($EAPI_STATUS_SUCCESS=0)

    Test 5:

    Buffer= char[20]

    Buflen = / (Keine Vorbelegung)

    Rückgabewert Buffer = String mit 5 Zeichen (müssen 5 Zeichen sein)

    Rückgabewert Buflen = 0

    => Kein Fehler wird zurückgegeben ($EAPI_STATUS_SUCCESS=0)


    Es sieht ein wenig so aus, als ob die DLL nicht das macht, was sie sollte - Oder?

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

  • Es sieht ein wenig so aus, als ob die DLL nicht das macht, was sie sollte - Oder?

    Das kann ich dir nicht sagen, weil ich die DLL nicht kenne. Eine kurze Google-Suche liefert mir das: https://www.yumpu.com/en/document/re…erface-picmg/21

    Und das scheint das zu bestätigen was in der Dokumentation steht.

    Kannst du mal das Skript posten mit dem du die Versuche gemacht hast? Vielleicht hast du ja da einen Fehler drin.

    • Offizieller Beitrag

    Laut Dokumentation ist das eine “__INOUT“ Funktion und daher habe ich “by reference“ angegeben, aber die Bufferlänge bleibt bei meiner Vorgabe.

    Häufig verwenden Dll folgenden Mechanismus: Aufruf der Dll mit allen Parametern und als Bufferlänge null (Wert "0" oder "Null"), dann wird die Bufferlänge auf den erforderlichen Wert gesetzt. Den Wert verwende ich dann um meinen Buffer auf die richtige Länge zu setzen und rufe dann die Dll korrekt auf. Ggf. muss zur Länge 1 addiert werden, falls der Buffer einen null-terminierten String halten soll (sowas steht in der Doku).

  • alpines :

    Hier ist mein vollständiger Testcode:

    Spoiler anzeigen

    BugFix :

    Häufig verwenden Dll folgenden Mechanismus: Aufruf der Dll mit allen Parametern und als Bufferlänge null (Wert "0" oder "Null"), dann wird die Bufferlänge auf den erforderlichen Wert gesetzt. Den Wert verwende ich dann um meinen Buffer auf die richtige Länge zu setzen und rufe dann die Dll korrekt auf. Ggf. muss zur Länge 1 addiert werden, falls der Buffer einen null-terminierten String halten soll (sowas steht in der Doku).

    Danke für die Idee, aber leider funktioniert es nicht. Aber im Anhang findest du die PDF mit der Dokumentation, falls du mal drüber schauen möchtest...


    Gruß

    Homer J. S.

  • $DllResult=DllCall($DllHandle, "uint:cdecl", "EApiBoardGetStringA", "uint", $EAPI_ID_BOARD_NAME_STR, "ptr", $pBuffer, "uint_ptr*" ,$pBuflen)

    Dein Parametertyp für $pBuflen ist "uint_ptr*", das wäre (wenn das überhaupt möglich ist in AutoIt, was es nicht ist) ein Pointer vom Pointer. Es darf aber nur ein einfacher Pointer sein -> "uint_ptr", "uint*" oder "ptr" nutzen!

    Du solltest für das Initialize und UnInitialize ebenfalls :cdecl nutzen, da diese auch API Calls sind und keine Std Calls.

  • Dein Parametertyp für $pBuflen ist "uint_ptr*", das wäre (wenn das überhaupt möglich ist in AutoIt, was es nicht ist) ein Pointer vom Pointer. Es darf aber nur ein einfacher Pointer sein -> "uint_ptr", "uint*" oder "ptr" nutzen!

    Du solltest für das Initialize und UnInitialize ebenfalls :cdecl nutzen, da diese auch API Calls sind und keine Std Calls.

    Das habe ich jetzt auch umgesetzt. An dem Problem mit der Bufferlänge hat sich nichts geändert. Allerdings ist das auch nicht wirklich ein Problem, da ich die Bufferlänge auch selbst nach dem Empfang ermitteln kann. Daher stelle ich jetzt das Thema auf gelöst. Vielen Dank für deine professionelle 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...

  • Homer J. S. 22. März 2019 um 10:34

    Hat das Label von [ offen ] auf [ gelöst ] geändert.
  • Hallo Zusammen,

    ich bin ein gutes Stück weiter gekommen mit dieser DLL. Allerdings habe ich ein Problem mit dem Aufruf der Funktion “EApiI2CWriteReadRaw“. Es wäre schön, wenn mir nochmal eine(r) auf die Sprünge helfen könnte.

    Hier der Aufruf aus der Dokumentation:

    Code
    EApiStatus_t EAPI_CALLTYPE EApiI2CWriteReadRaw (__IN EApiId_t Id, __IN uint8_t Addr, __INOPT void* pWBuffer, __IN uint32_t WriteBCnt, __OUTOPT void *pRBuffer, __IN uint32_t RBufLen, __IN uint32_t ReadBCnt)

    Hier mein Aufruf mit AutoIt (Auszug):

    Code
    $tWBuffer=DllStructCreate("ptr")
    $pWBuffer=DllStructGetPtr($tWBuffer, 1)
    DllStructSetData($tWBuffer, 1, Null)
    $tRBuffer=DllStructCreate("ptr")
    $pRBuffer=DllStructGetPtr($tRBuffer, 1)
    $DllResult=DllCall($DllHandle, "uint:cdecl", "EApiI2CWriteReadRaw", "unit", 0, "byte", 0xA0, "ptr", $pWBuffer ,"uint", 0, "ptr", $pRBuffer, "uint", 1, "uint", 1)

    Wenn ich dieses so Aufrufe, dann gibt mir @error eine 1 zurück.

    Link zu Dokumentation aus Post #9 (ab Seite 10): Dokumentation


    Vielen Dank schonam für eure 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...

    Einmal editiert, zuletzt von Homer J. S. (9. April 2019 um 22:32)

  • Homer J. S. 9. April 2019 um 22:30

    Hat das Label von [ gelöst ] auf [ offen ] geändert.
  • Dein Parametertyp vom 1. Parameter ist "unit". Du hast einen Tippfehler drin.

    Upps, wie peinlich. Dies habe ich soeben geändert und jetzt gibt mir die DLL "EAPI_STATUS_INVALID_PARAMETER" zurück ;(.


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

  • Deine Buffer sind falsch. Es wird ein void* erwartet, d.h. du übergibst einen Pointer der auf ein unbestimmtes Datenfeld zeigt, der Typ kann nachträglich zu int, char, was auch immer gecastet werden.

    Was du übergibst ist ein void**. Schau dir an was in den Funktionen davon als Buffer verwendet wird (ich schätze mal int[] oder char[] respektive byte[]) und erzeug daraus ein Struct wessen Pointer du übergibst.

    Das gilt sowohl für pWBuffer als auch für pRBuffer.

  • alpines: Ich musste beruflich kurzfristig verreisen, deshalb sorry für die späte Antwort.

    Was du übergibst ist ein void**. Schau dir an was in den Funktionen davon als Buffer verwendet wird (ich schätze mal int[] oder char[] respektive byte[])

    Du hattest mal wieder Recht. Ich habe es jetzt wie folgt erfolgreich umgesetzt:

    Vielen Dank für deine Hilfe/Unterstützung!

    Gruß

    Homer J. S.

    PS: Ich setzte das Thema wieder auf gelöst

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

    Einmal editiert, zuletzt von Homer J. S. (12. April 2019 um 18:26)

  • Homer J. S. 12. April 2019 um 18:12

    Hat das Label von [ offen ] auf [ gelöst ] geändert.