Seltsamer DllCallback/DllCall Error

  • In folgendem Code tauchen sporadisch seltsame Fehler auf die ich mir momentan nicht wirklich erklären kann. Manchmal läuft der Code ohne Probleme durch, manchmal werden Fehler wie "undeclared Variable" angezeigt an Stellen wo gar keine Variable ist. Manchmal stürzt AutoIt ohne jegliche Rückmeldung ab.

    Spoiler anzeigen
    [autoit]


    ; -Author: name22 (http://www.autoit.de)

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $WT_EXECUTEDEFAULT = 0x00000000
    Global Const $WT_EXECUTEINIOTHREAD = 0x00000001
    Global Const $WT_EXECUTEINTIMERTHREAD = 0x00000020
    Global Const $WT_EXECUTEINPERSISTENTTHREAD = 0x00000080
    Global Const $WT_EXECUTELONGFUNCTION = 0x00000010
    Global Const $WT_EXECUTEONLYONCE = 0x00000008
    Global Const $WT_TRANSFER_IMPERSONATION = 0x00000100

    [/autoit] [autoit][/autoit] [autoit]

    $hDll_Kernel32 = DllOpen("kernel32.dll")

    [/autoit] [autoit][/autoit] [autoit]

    $hCallBack = DllCallbackRegister("_Callback", "NONE", "LPARAM;INT")
    $hTimer = _CreateTimerQueueTimer($hCallBack, 12345, 200, 200, Default, Default, $hDll_Kernel32)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Before Callback" & @CRLF)
    Sleep(2000)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Deleting: " & _DeleteTimerQueueTimer($hTimer, 0, 0, $hDll_Kernel32) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Sleep(1000)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("After Callback" & @CRLF)
    DllClose($hDll_Kernel32)
    DllCallbackFree($hCallBack)

    [/autoit] [autoit][/autoit] [autoit]

    Func _Callback($lParam, $TimerOrWaitFired)
    ConsoleWrite("Callback Parameter: " & $lParam & @CRLF)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _CreateTimerQueueTimer($hTimer_Callback, $iParameter, $iDueTime, $iPeriod = 0, $iFlags = $WT_EXECUTEDEFAULT, $hTimerQueue = 0, $hDll_Kernel32 = "kernel32.dll")
    Local $thTimerHandle = DllStructCreate("HANDLE")
    Local $aRes = DllCall($hDll_Kernel32, "BOOL", "CreateTimerQueueTimer", "PTR", DllStructGetPtr($thTimerHandle), "HANDLE", 0, "PTR", DllCallbackGetPtr($hTimer_Callback), "INT", $iParameter, "DWORD", $iDueTime, "DWORD", $iPeriod, "ULONG", $iFlags)
    If @error Then Return SetError(@error, @extended, 0)
    If Not $aRes[0] Then Return SetError(2, 0, 0)
    Return DllStructGetData($thTimerHandle, 1)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _DeleteTimerQueueTimer($hTimer, $hCompletionEvent = 0, $hTimerQueue = 0, $hDll_Kernel32 = "kernel32.dll")
    Local $aRes = DllCall($hDll_Kernel32, "BOOL", "DeleteTimerQueueTimer", "HANDLE", $hTimerQueue, "HANDLE", $hTimer, "HANDLE", $hCompletionEvent)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRes[0]
    EndFunc

    [/autoit]


    Hier sind noch die Links zu MSDN Artikeln der Kernelfunktionen die ich versuche zu verwenden:
    http://msdn.microsoft.com/de-de/library/…esktop/ms682485
    http://msdn.microsoft.com/de-de/library/…esktop/ms682569
    Alle Timer werden für die Default TimerQueue erstellt, somit sollte das Löschen der Liste nicht nötig sein.

    PS: Ich suche nicht nach einer Alternative zu diesen Timern, sondern nach einer Lösung für dieses Problem ;).

  • Es freut mich zu hören, dass es zumindest bei einer Person funktioniert ^^. Zwei andere User (vermutlich Win 7) haben auch schon getestet und hatten das selbe Ergebnis wie ich.
    Kann sich irgendjemand vorstellen wieso das scheinbar vom Betriebssystem abhängt?

  • Wenn man das Script etwas verändert, dann gibt es unter XP auch manchmal diese seltsamen Abstürze:

    Spoiler anzeigen
    [autoit]

    Global Const $WT_EXECUTEDEFAULT = 0x00000000
    Global Const $WT_EXECUTEINIOTHREAD = 0x00000001
    Global Const $WT_EXECUTEINTIMERTHREAD = 0x00000020
    Global Const $WT_EXECUTEINPERSISTENTTHREAD = 0x00000080
    Global Const $WT_EXECUTELONGFUNCTION = 0x00000010
    Global Const $WT_EXECUTEONLYONCE = 0x00000008
    Global Const $WT_TRANSFER_IMPERSONATION = 0x00000100

    [/autoit] [autoit][/autoit] [autoit]

    $hDll_Kernel32 = DllOpen("kernel32.dll")

    [/autoit] [autoit][/autoit] [autoit]

    $hCallBack = DllCallbackRegister("_Callback", "NONE", "LPARAM;INT")
    $hTimer = _CreateTimerQueueTimer($hCallBack, 12345, 200, 200, Default, Default, $hDll_Kernel32)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Before Callback" & @CRLF)
    $iCnt = 0
    For $i = 1 To 2000
    $iCnt += 1
    _Print($iCnt)
    Sleep(10)
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("Deleting: " & _DeleteTimerQueueTimer($hTimer, 0, 0, $hDll_Kernel32) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Sleep(1000)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("After Callback" & @CRLF)
    DllClose($hDll_Kernel32)
    DllCallbackFree($hCallBack)

    [/autoit] [autoit][/autoit] [autoit]

    Func _Callback($lParam, $TimerOrWaitFired)
    ConsoleWrite("Callback Parameter: " & $lParam & @CRLF)
    EndFunc ;==>_Callback

    [/autoit] [autoit][/autoit] [autoit]

    Func _CreateTimerQueueTimer($hTimer_Callback, $iParameter, $iDueTime, $iPeriod = 0, $iFlags = $WT_EXECUTEDEFAULT, $hTimerQueue = 0, $hDll_Kernel32 = "kernel32.dll")
    Local $thTimerHandle = DllStructCreate("HANDLE")
    Local $aRes = DllCall($hDll_Kernel32, "BOOL", "CreateTimerQueueTimer", "PTR", DllStructGetPtr($thTimerHandle), "HANDLE", 0, "PTR", DllCallbackGetPtr($hTimer_Callback), "INT", $iParameter, "DWORD", $iDueTime, "DWORD", $iPeriod, "ULONG", $iFlags)
    If @error Then Return SetError(@error, @extended, 0)
    If Not $aRes[0] Then Return SetError(2, 0, 0)
    Return DllStructGetData($thTimerHandle, 1)
    EndFunc ;==>_CreateTimerQueueTimer

    [/autoit] [autoit][/autoit] [autoit]

    Func _DeleteTimerQueueTimer($hTimer, $hCompletionEvent = 0, $hTimerQueue = 0, $hDll_Kernel32 = "kernel32.dll")
    Local $aRes = DllCall($hDll_Kernel32, "BOOL", "DeleteTimerQueueTimer", "HANDLE", $hTimerQueue, "HANDLE", $hTimer, "HANDLE", $hCompletionEvent)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRes[0]
    EndFunc ;==>_DeleteTimerQueueTimer

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Print($sText)
    Local $sPrint = "! "
    $sPrint = $sPrint & $sText & @CRLF
    ConsoleWrite($sPrint)
    EndFunc ;==>_Print

    [/autoit]

    Dieses Verhalten ist mir schon lange bekannt, weshalb ich bei meinen Scripten die CallBackfunktionen immer in eine Dll "auslagere" (z.B.: Bass UDF)
    Es scheint, als würde die Callbackfunktion zu einem ungünstigen Zeitpunkt aufgerufen und AutoIt damit auf dem falschen Fuß erwischt werden...
    Wo genau das Problem liegt, kann ich aber nicht sagen.

    Zum experimentieren hab ich hier noch ein Script: autoit.de/wcf/attachment/16717/
    Manchmal stimmt auch der Rückgabewert an die Dll nicht!

    E

  • Das Problem gibt es auch manchmal mit ASM.
    Bei mir ist das passiert wenn ich $WM_NCHITTEST registriert habe um damit das Fenster zu bewegen.
    Das hat scheinbar manchmal zu einem ungünstigen Zeitpunkt (vllt im ASM?) dazwischengefunkt und das Programm ist abgeschmiert.

    Leider habe ich kein funktionierendes Beispiel, weil ich alle Skripte dahingehend geändert habe, dass dieser Fehler nicht auftreten kann.