Jump to content

Another AutoIt x64 hard crash, using Timers


Recommended Posts

I want to be able to make a single-access timer (actually a timeout). This code works in 32-bit, but hard crashes in 64-bit:

#include <Timers.au3>

_Timer_SetTimer(WinGetHandle(AutoItWinGetTitle()), 6000, "__TimeoutCall")

While Sleep(1000)
WEnd

Func __TimeoutCall($hwnd, $Msg, $iIDTimer, $dwTime)
    ;#forceref $hWnd, $Msg, $iIDTimer, $dwTim
    _Timer_KillTimer($hwnd, $iIDTimer) ;First, kill our own timer so that we don't repeat the commands.
    ConsoleWrite("timer")
EndFunc

Although I am aware that I can use Adlib functions, I would prefer to use Timers.au3.

Is killing the timer inside the timer callback function a no-no for some reason?

Who else would I be?
Link to comment
Share on other sites

I read MSDN and can't see why it should crashing. Though still think it's best to use native functions over UDFs.

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Link to comment
Share on other sites

This is a bug. Problem is DllCallbackFree from within callback function. This is a Workaround.

#include <Timers.au3>

Global $hCallBack = DllCallbackRegister("__TimeoutCall", "none", "hwnd;int;uint_ptr;dword")
DllCall("user32.dll", "uint_ptr", "SetTimer", "hwnd", AutoItWinGetTitle(), "uint_ptr", 1001, "uint", 5000, "ptr", DllCallbackGetPtr($hCallBack))
Global $bCallbackFree = False

While Sleep(1000)
    If $bCallbackFree Then  DllCallbackFree($hCallBack)
WEnd

Func __TimeoutCall($hwnd, $Msg, $iIDTimer, $dwTime)
    ;#forceref $hWnd, $Msg, $iIDTimer, $dwTim

    DllCall("user32.dll", "bool", "KillTimer", "hwnd", $hwnd, "uint_ptr", $iIDTimer)
    $bCallbackFree = True
    ConsoleWrite("timer" & @LF)
EndFunc

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

I had this problem once... I solved the problem by killing the timer outside the timer function. (equivalent to that funkey offers)

#include <Timers.au3>

$kill = False

$timer = _Timer_SetTimer(WinGetHandle(AutoItWinGetTitle()) , 6000, "__TimeoutCall")

While Sleep(1000)
    If $kill Then _Timer_KillTimer(WinGetHandle(AutoItWinGetTitle()), $timer) ;First, kill our own timer so that we don't repeat the commands.
WEnd

Func __TimeoutCall($hwnd, $Msg, $iIDTimer, $dwTime)
    ;#forceref $hWnd, $Msg, $iIDTimer, $dwTim
    $kill = True
    ConsoleWrite("timer")
EndFunc
Link to comment
Share on other sites

Well, well.

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Link to comment
Share on other sites

Thank you all for your suggestions, but I don't think the workaround will work for me. I don't see a way to have this workaround with extremely small timeouts (such as 50 ms) without also having an extremely tight main loop.

Please allow me to post my entire code so you can make a recommendation. Here is SetTimeout.au3:

#include-once
#include <Array.au3>
#include <Timers.au3>
#include "param.au3"
Global $g_TimersArray[1][3]
Global Enum $g_TimerID, $g_TimerFunc, $g_TimerParam

Func _SetTimeout($time, $function, $params = -1)
    Local $index = ($g_TimersArray[0][0] = "") ? 0 : UBound($g_TimersArray)
    Local $iIDTimer = _Timer_SetTimer(WinGetHandle(AutoItWinGetTitle()), $time, "__TimeoutCall")
    If $index <> 0 Then ReDim $g_TimersArray[$index + 1][3]
    $g_TimersArray[$index][$g_TimerID] = $iIDTimer
    $g_TimersArray[$index][$g_TimerFunc] = FuncName($function)
    $g_TimersArray[$index][$g_TimerParam] = $params
    Return $iIDTimer
EndFunc

Func _SetTimeoutCancel($iIDTimer)
    _Timer_KillTimer(WinGetHandle(AutoItWinGetTitle()), $iIDTimer)
    For $i = 0 To UBound($g_TimersArray) - 1
        If $iIDTimer = $g_TimersArray[$i][$g_TimerID] Then
            If $i = 0 Then
                $g_TimersArray[0][0] = ""
                $g_TimersArray[0][1] = ""
                $g_TimersArray[0][2] = ""
            Else
                _ArrayDelete($g_TimersArray, $i)
            EndIf
            Return
        EndIf
    Next
EndFunc

Func __TimeoutCall($hwnd, $Msg, $iIDTimer, $dwTime)
    #forceref $hWnd, $Msg, $iIDTimer, $dwTime
    _Timer_KillTimer($hwnd, $iIDTimer) ;First, kill our own timer so that we don't repeat the commands.
    For $i = 0 To UBound($g_TimersArray) - 1
        If $iIDTimer = $g_TimersArray[$i][$g_TimerID] Then

            If Not IsArray($g_TimersArray[$i][$g_TimerParam]) Then
                Call($g_TimersArray[$i][$g_TimerFunc])
            Else
                Call($g_TimersArray[$i][$g_TimerFunc], $g_TimersArray[$i][$g_TimerParam])
            EndIf
            If $i = 0 Then
                $g_TimersArray[0][0] = ""
                $g_TimersArray[0][1] = ""
                $g_TimersArray[0][2] = ""
            Else
                _ArrayDelete($g_TimersArray, $i)
            EndIf
            ExitLoop
        EndIf
    Next
EndFunc

And param.au3:

#include-once
Func param($1=0, $2=0, $3=0, $4=0, $5=0, $6=0, $7=0, $8=0, $9=0, $10=0, $11=0, $12=0, $13=0, $14=0, $15=0, $16=0, $17=0, $18=0, $19=0, $20=0, $21=0, $22=0, $23=0, $24=0, $25=0, $26=0, $27=0, $28=0, $29=0, $30=0, $31=0, $32=0, $33=0, $34=0, $35=0, $36=0, $37=0, $38=0, $39=0, $40=0, $41=0, $42=0, $43=0, $44=0, $45=0, $46=0, $47=0, $48=0, $49=0, $50=0, $51=0, $52=0, $53=0, $54=0, $55=0, $56=0, $57=0, $58=0, $59=0, $60=0, $61=0, $62=0, $63=0, $64=0, $65=0, $66=0, $67=0, $68=0, $69=0, $70=0, $71=0, $72=0, $73=0, $74=0, $75=0, $76=0, $77=0, $78=0, $79=0, $80=0, $81=0, $82=0, $83=0, $84=0, $85=0, $86=0, $87=0, $88=0, $89=0, $90=0, $91=0, $92=0, $93=0, $94=0, $95=0, $96=0, $97=0, $98=0, $99=0, $100=0, $101=0, $102=0, $103=0, $104=0, $105=0, $106=0, $107=0, $108=0, $109=0, $110=0, $111=0, $112=0, $113=0, $114=0, $115=0, $116=0, $117=0, $118=0, $119=0, $120=0, $121=0, $122=0, $123=0, $124=0, $125=0, $126=0, $127=0, $128=0, $129=0, $130=0, $131=0, $132=0, $133=0, $134=0, $135=0, $136=0, $137=0, $138=0, $139=0, $140=0, $141=0, $142=0, $143=0, $144=0, $145=0, $146=0, $147=0, $148=0, $149=0, $150=0, $151=0, $152=0, $153=0, $154=0, $155=0, $156=0, $157=0, $158=0, $159=0, $160=0, $161=0, $162=0, $163=0, $164=0, $165=0, $166=0, $167=0, $168=0, $169=0, $170=0, $171=0, $172=0, $173=0, $174=0, $175=0, $176=0, $177=0, $178=0, $179=0, $180=0, $181=0, $182=0, $183=0, $184=0, $185=0, $186=0, $187=0, $188=0, $189=0, $190=0, $191=0, $192=0, $193=0, $194=0, $195=0, $196=0, $197=0, $198=0, $199=0, $200=0, $201=0, $202=0, $203=0, $204=0, $205=0, $206=0, $207=0, $208=0, $209=0, $210=0, $211=0, $212=0, $213=0, $214=0, $215=0, $216=0, $217=0, $218=0, $219=0, $220=0, $221=0, $222=0, $223=0, $224=0, $225=0, $226=0, $227=0, $228=0, $229=0, $230=0, $231=0, $232=0, $233=0, $234=0, $235=0, $236=0, $237=0, $238=0, $239=0, $240=0, $241=0, $242=0, $243=0, $244=0, $245=0, $246=0, $247=0, $248=0, $249=0, $250=0, $251=0, $252=0, $253=0, $254=0, $255=0)
    Local $arr[@NumParams + 1] = ["CallArgArray"]
    For $i = 1 To @NumParams
        $arr[$i] = Eval($i)
    Next
    Return $arr
EndFunc

An example of how this might be used is as follows:

#include "SetTimeout.au3"

ToolTip("Hi, there")
_SetTimeout(1000, ToolTip, param(''))

Sleep(5000)

Now the above example is minimal. The real meat of how I use this function on a daily basis is in "breaking out" of functions that are already callbacks, and must return quickly.

Partial code example (I can post FolderMonitor.au3 if someone wants it):

#include "FolderMonitor.au3"
#include "SetTimeout.au3"

_Folder_Monitor("C:\", FolderChange, $SHCNE_RENAMEFOLDER)

Func FolderChange($iEvent, $sFolder, $sFolderNew)
    Switch $iEvent
        Case $SHCNE_RENAMEFOLDER
            ; Apparently, the shell waits for this function to complete before moving on with the rename, so we need to return quickly.
            ; For this reason, we exit from this function by setting a timer to come back to what we really want to do.
            _SetTimeout(50, RenameFolder, param($sFolder, $sFolderNew))
    EndSwitch
EndFunc   ;==>FolderChange

Based on the workarounds given, I don't see how I can modify SetTimeout.au3 so that execution of functions only happens once, and no more. Especially when I don't want to have a while loop in SetTimeout.au3

Does anyone have suggestions for using such a workaround in relation to this code?

Who else would I be?
Link to comment
Share on other sites

Well, and idea that comes to my mind...

- Use a scripting.dictionary object (stack) to store that changes

- In FolderChange() add the change to the stack and call a processing function with AdlibRegister()

- Process the stack's items in the processing function and only unregister the Adlib (from within the adlib function) if the stack's size = 0 at the end of the function

Link to comment
Share on other sites

You could start an adlib before leaving __TimeoutCall() to release the $hCallback. But before you have to change _Timer_KillTimer() to not free the DllCallback. and save the $hCallback in a global variable.

Edited by funkey

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

Thanks, funkey. I was afraid something like that would be necessary. Looks like I'll be reworking most UDF functions for x64 compatibility before long (lol). Altough I would rather hope that the bugs just get fixed.

Since this is, indeed, a bug, should I submit it to trac or something?

Who else would I be?
Link to comment
Share on other sites

In my experience the scripting dictionary object is really fast and stack operations are easy to implement, but you're right, a global array should work all the same (though you would need to "emulate" the stack character for the array with some extra code).

Link to comment
Share on other sites

Try this SetTimeout.au3 (I can't test, because I'm on 3.3.8.1)

 

Edit: You have to add the new global variable to your $g_TimersArray, if you start more than one timeout. And then you Need another global variable to tell the adlib function which callback should be released. No nice solution.

#include-once
#include <Array.au3>
#include <Timers.au3>
#include "param.au3"

Global $g_TimersArray[1][3]
Global $g_hCallback ;new line
Global Enum $g_TimerID, $g_TimerFunc, $g_TimerParam


Func _SetTimeout($time, $function, $params = -1)
    Local $index = ($g_TimersArray[0][0] = "") ? 0 : UBound($g_TimersArray)
    Local $iIDTimer = _Timer_SetTimer(WinGetHandle(AutoItWinGetTitle()), $time, "__TimeoutCall")
    If $index <> 0 Then ReDim $g_TimersArray[$index + 1][3]
    $g_TimersArray[$index][$g_TimerID] = $iIDTimer
    $g_TimersArray[$index][$g_TimerFunc] = FuncName($function)
    $g_TimersArray[$index][$g_TimerParam] = $params
    $g_hCallback = $_Timers_aTimerIDs[$_Timers_aTimerIDs[0][0]][2]  ;new line
    $_Timers_aTimerIDs[$_Timers_aTimerIDs[0][0]][2] = 0 ;new line (to prevent _Timer_KillTimer to free the DllCallback)
    Return $iIDTimer
EndFunc

Func _SetTimeoutCancel($iIDTimer)
    _Timer_KillTimer(WinGetHandle(AutoItWinGetTitle()), $iIDTimer)
    For $i = 0 To UBound($g_TimersArray) - 1
        If $iIDTimer = $g_TimersArray[$i][$g_TimerID] Then
            If $i = 0 Then
                $g_TimersArray[0][0] = ""
                $g_TimersArray[0][1] = ""
                $g_TimersArray[0][2] = ""
            Else
                _ArrayDelete($g_TimersArray, $i)
            EndIf
            Return
        EndIf
    Next
EndFunc

Func __TimeoutCall($hwnd, $Msg, $iIDTimer, $dwTime)
    #forceref $hWnd, $Msg, $iIDTimer, $dwTime
    _Timer_KillTimer($hwnd, $iIDTimer) ;First, kill our own timer so that we don't repeat the commands.
    For $i = 0 To UBound($g_TimersArray) - 1
        If $iIDTimer = $g_TimersArray[$i][$g_TimerID] Then

            If Not IsArray($g_TimersArray[$i][$g_TimerParam]) Then
                Call($g_TimersArray[$i][$g_TimerFunc])
            Else
                Call($g_TimersArray[$i][$g_TimerFunc], $g_TimersArray[$i][$g_TimerParam])
            EndIf
            If $i = 0 Then
                $g_TimersArray[0][0] = ""
                $g_TimersArray[0][1] = ""
                $g_TimersArray[0][2] = ""
            Else
                _ArrayDelete($g_TimersArray, $i)
            EndIf
            ExitLoop
        EndIf
    Next
    AdlibRegister("__TimeoutCall_Release", 100) ;new line
EndFunc

;new function
Func __TimeoutCall_Release()
    AdlibUnRegister("__TimeoutCall_Release")
    DllCallbackFree($g_hCallback)
EndFunc
Edited by funkey

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

Thanks, funkey. Since your suggestion, I decided to replace the KillTimer with a local copy that does what I need. Here is my finalized code that works perfectly:

#include-once
#include <Array.au3>
#include <Timers.au3>
#include "param.au3"
Global $g_TimersArray[1][3]
Global Enum $g_TimerID, $g_TimerFunc, $g_TimerParam
Global $g_TimerCallbacks[1]

Func _SetTimeout($time, $function, $params = -1)
    Local $index = ($g_TimersArray[0][0] = "") ? 0 : UBound($g_TimersArray)
    Local $iIDTimer = _Timer_SetTimer(WinGetHandle(AutoItWinGetTitle()), $time, "__Timeout_Call")
    If $index <> 0 Then ReDim $g_TimersArray[$index + 1][3]
    $g_TimersArray[$index][$g_TimerID] = $iIDTimer
    $g_TimersArray[$index][$g_TimerFunc] = FuncName($function)
    $g_TimersArray[$index][$g_TimerParam] = $params
    Return $iIDTimer
EndFunc

Func _SetTimeout_Cancel($iIDTimer)
    __Timeout_KillTimer(WinGetHandle(AutoItWinGetTitle()), $iIDTimer)
    For $i = 0 To UBound($g_TimersArray) - 1
        If $iIDTimer = $g_TimersArray[$i][$g_TimerID] Then
            If $i = 0 Then
                $g_TimersArray[0][0] = ""
                $g_TimersArray[0][1] = ""
                $g_TimersArray[0][2] = ""
            Else
                _ArrayDelete($g_TimersArray, $i)
            EndIf
            Return
        EndIf
    Next
EndFunc

Func __Timeout_Call($hwnd, $Msg, $iIDTimer, $dwTime)
    #forceref $hWnd, $Msg, $iIDTimer, $dwTime
    __Timeout_KillTimer($hwnd, $iIDTimer) ;First, kill our own timer so that we don't repeat the commands.
    For $i = 0 To UBound($g_TimersArray) - 1
        If $iIDTimer = $g_TimersArray[$i][$g_TimerID] Then
            If Not IsArray($g_TimersArray[$i][$g_TimerParam]) Then
                Call($g_TimersArray[$i][$g_TimerFunc])
            Else
                Call($g_TimersArray[$i][$g_TimerFunc], $g_TimersArray[$i][$g_TimerParam])
            EndIf
            If $i = 0 Then
                $g_TimersArray[0][0] = ""
                $g_TimersArray[0][1] = ""
                $g_TimersArray[0][2] = ""
            Else
                _ArrayDelete($g_TimersArray, $i)
            EndIf
            ExitLoop
        EndIf
    Next
EndFunc

Func __Timeout_KillTimer($hWnd, $iTimerID)
    Local $aResult[1] = [0], $hCallBack = 0, $iUBound = UBound($_Timers_aTimerIDs) - 1
    For $x = 1 To $iUBound
        If $_Timers_aTimerIDs[$x][0] = $iTimerID Then
            If IsHWnd($hWnd) Then
                $aResult = DllCall("user32.dll", "bool", "KillTimer", "hwnd", $hWnd, "uint_ptr", $_Timers_aTimerIDs[$x][1])
            Else
                $aResult = DllCall("user32.dll", "bool", "KillTimer", "hwnd", $hWnd, "uint_ptr", $_Timers_aTimerIDs[$x][0])
            EndIf
            If @error Or $aResult[0] = 0 Then Return SetError(@error, @extended, False)
            $hCallBack = $_Timers_aTimerIDs[$x][2]
            If $hCallBack <> 0 Then
                Local $index = ($g_TimerCallbacks[0] = "") ? 0 : UBound($g_TimerCallbacks)
                If $index <> 0 Then ReDim $g_TimerCallbacks[$index + 1]
                $g_TimerCallbacks[$index] = $hCallBack
                AdlibRegister(__Timeout_Free, 6000) ; Assume 6 seconds is enough time for the __Timeout_Call'd function to run.
            EndIf
            For $i = $x To $iUBound - 1
                $_Timers_aTimerIDs[$i][0] = $_Timers_aTimerIDs[$i + 1][0]
                $_Timers_aTimerIDs[$i][1] = $_Timers_aTimerIDs[$i + 1][1]
                $_Timers_aTimerIDs[$i][2] = $_Timers_aTimerIDs[$i + 1][2]
            Next
            ReDim $_Timers_aTimerIDs[UBound($_Timers_aTimerIDs - 1)][3]
            $_Timers_aTimerIDs[0][0] -= 1
            ExitLoop
        EndIf
    Next
    Return $aResult[0] <> 0
EndFunc   ;==>_Timer_KillTimer

Func __Timeout_Free()
    AdlibUnRegister(__Timeout_Free)
    For $i = UBound($g_TimerCallbacks) - 1 To 0 Step -1 ; Reverse so that when we _ArrayDelete we won't go out of bounds
        DllCallbackFree($g_TimerCallbacks[$i])
        If $i = 0 Then
            $g_TimerCallbacks[0] = ''
        Else
            _ArrayDelete($g_TimerCallbacks, $i)
        EndIf
    Next
EndFunc
Who else would I be?
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...