Profifrage: AutoIT crasht mit meiner (selbstgemachten) C++ .dll

  • moin,

    ich hab mir eine .dll in c++ geschrieben und möchte sie in autoit verwenden ... leider hab ich jetzt das problem, dass autoit immer crasht.
    Ich konnte feststellen, dass die wie gewünscht die funktion die ich per dllcall aufrufe (siehe script) immer komplett, fehlerfrei durchläuft.
    Nur danach passiert irgendwas, was autoit crasht...

    In der anlage befindet sich mein c++ source ....

    hier mein Autoitcode der das ganze (mir unerklärlicher weise) beim DllCall crasht:

    [autoit]

    Func _Rechnen()
    $Open = DllOpen("DLLtest.dll")
    $return = DllCall ($Open, "BOOLEAN", "FileRead", "str" ,"test.dat")
    MsgBox (1,"error", @error)
    MsgBox (64, "Ergebnis", "Das Ergebnis lautet " & $return[0])
    EndFunc

    [/autoit]

    3 Mal editiert, zuletzt von WhiteLion (30. März 2012 um 19:06)

  • ja, ich hatte rumprobiert und dabei ging bei der angehängten version der * unter ... also bitte beachten, im anhang fehlt er ... oben im code ist er vorhanden ... also nicht wundern. aber daran liegt/lag es leider nicht. ...

    EDIT: ich habe die version oben nochmal updated ....

  • Hi

    das Problem ist schnell gelöst. Du exportierst die Funktionen mit cdecl und rufst sie in Autoit mit stdcall und dann knallt das natürlich.

    [autoit]

    $return = DllCall ($Open, "BOOL:cdecl", "FileRead", "str" ,"test.dat")

    [/autoit]


    Ruf die Dll einfach so auf und es funktioniert.

  • Danke Sprenger, hab's jetzt installiert. (Nachdem ich das ganze mit Code:Blocks kompiliert und getestet habe und zu dem gleichen Ergebnis wie du gekommen bin.
    Komisch ist nur, dass auch ohne :cdecl die Funktion aufgerufen wurde und die DLL eine Ausgabe in die Scite Konsole machen konnte. Deswegen bin ich nicht gleich darauf gekommen.

  • Hi

    das Problem ist schnell gelöst. Du exportierst die Funktionen mit cdecl und rufst sie in Autoit mit stdcall und dann knallt das natürlich.

    [autoit]

    $return = DllCall ($Open, "BOOL:cdecl", "FileRead", "str" ,"test.dat")

    [/autoit]


    Ruf die Dll einfach so auf und es funktioniert.

    danke ! hat geklappt .... könntest du/jemand mir den technischen unterschied erklären ?

    EDIT: ich nehme die Datei erstmal aus den anhängen raus und arbeite weiter an der dll ... sie sollte erheblich schneller sein als alles was in autoit erstellt wurde .... wenn sie fertig ist, stelle ich sie hier zur verfügung + tutorial, deswegen auch die vielen comments :D

    3 Mal editiert, zuletzt von WhiteLion (30. März 2012 um 15:03)

  • Hi

    bei cdecl muss der, der eine Funktion aufgerufen hat danach den Stack bereinigen (In dem Fall also Autoit)
    bei stdcall wird der Stack von der Aufgerufenen Funktion bereinigt

    Da bei beiden der Aufruf identisch ist sind auch die Konsolenausgaben da.
    Das Problem entsteht erst nach dem Aufruf, da Autoit denkt der Stack wird der aufgerufenen Funktion bereinigt und sie denkt Autoit macht das. Also ist nach dem Aufruf der Stack nicht mehr zu gebrauchen und Absturz.

  • Hi,
    genauer gesagt stehen beim Aufruf des DllCall´s auf dem Stack die Rücksprungadresse und dann nacheinander die Parameter der Funktion.
    Damit nach dem Abarbeiten der Dll-Funktion das Programm den "Rückweg" in das AutoItscript findet, braucht es natürlich die richtige Adresse im Speicher (im AutoItscript die Adresse das nächsten Befehls nach dem DllCall)

    Beispiel1:
    Das Programm ruft die DLL-Funktion mit cdecl auf. Es wird also die Rücksprungadresse und dann 3 Parameter INT (also zusammen 12 Byte) auf den Stack gepushed.
    Nach Ablauf der Dll-Funktion (diese ist per cdecl deklariert) weiss der Compiler, dass das aufrufende Programm den Stack aufzuräumen hat und setzt ans Ende der Funktion ein einfaches RET.
    Das aufrufende Programm (AutoIt) weiss nun, dass es die Dll mit cdecl aufgerufen hat, POP´t nun die 12Bytes vom Stack und findet dann dort die Rücksprungadresse. Alles glatt gelaufen ^^

    Beispiel2:
    Das Programm ruft die DLL-Funktion mit cdecl auf. Es wird also die Rücksprungadresse und dann 3 Parameter INT (also zusammen 12 Byte) auf den Stack gepushed.
    Nach Ablauf der Dll-Funktion (diese ist per stdcall deklariert) weiss der Compiler, dass das aufrufende Programm den Stack NICHT aufräumt und setzt ans Ende der Funktion ein RET 12. Dadurch werden die 12 Bytes vom Stack gePOPt!!!
    Das aufrufende Programm (AutoIt) weiss nun, dass es die Dll mit cdecl aufgerufen hat, POP´t nun AUCH NOCH 12Bytes vom Stack und findet dann dort eine Rücksprungadresse. Und genau an diese Speicherstelle wird dann auch hingesprungen.....Irgendwo mitten in den Speicher, BÄÄM, crash...

  • danke für diese wirklich ausführliche/n erklärung/en
    und die großartige hilfe :) - wieder was gelernt ! ... eine letzte
    frage hab ich allerdings noch: wie muss ich den in C++ die
    funktion "einleiten", damit ich sie in autoit per stdcall aufrufen kann bzw, ohne "cdecl" ?

  • :thumbup: