marko29 Posted February 28, 2011 Share Posted February 28, 2011 (edited) If you press button 1 it will normally start a while loop and when you press button 2 the msg will be invoked and show a consolewrite. BUT If the button 1 function starts with the timer, it will completely block everything, as well as message that is sent to gui with button 2. Also note that hotkey is completely ignored/doesnt trigger if this function starts with timer. After days and days of debugging i came to this and made up short script to show it. I really need timers to trigger my function that needs to receive message but how if messages are blocked when function starts with timer? Could it be that timers are perhaps started on another thread? expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <Timers.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> ; Set a HotKey HotKeySet("x", "_Interrupt") ; Declare a flag $fInterrupt = 0 $started = 0 $hGUI = GUICreate("Test", 500, 500) $hButton_1 = GUICtrlCreateButton("Func One", 10, 10, 80, 30) $hButton_2 = GUICtrlCreateButton("Func Two", 10, 50, 80, 30) ; Create a dummy control for the Accelerator to action when pressed $hAccelInterupt = GUICtrlCreateDummy() ; Set an Accelerator key to action the dummy control Dim $AccelKeys[1][2]=[ ["z", $hAccelInterupt] ] GUISetAccelerators($AccelKeys) GUISetState() ; Intercept Windows command messages with out own handler GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND") $timer = _Timer_SetTimer($hGUI, 10000, "timerfunc") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $hButton_1 _Func_1() Case $hButton_2 _Func_2() EndSwitch WEnd Func _Func_1() $started = 1 while 1 ConsoleWrite("Sleeping..."&@LF) Sleep(2000) WEnd EndFunc Func _Func_2() ConsoleWrite(">Func 2" & @CRLF) EndFunc Func _Interrupt() ; The HotKey was pressed so set the flag $fInterrupt = 2 EndFunc Func _WM_COMMAND($hWnd, $Msg, $wParam, $lParam) ; The Func 2 button was pressed so set the flag If BitAND($wParam, 0x0000FFFF) = $hButton_2 Then ConsoleWrite("+BUTTON 2 PRESSED" & @CRLF) ; The dummy control was actioned by the Accelerator key so set the flag If BitAND($wParam, 0x0000FFFF) = $hAccelInterupt Then $fInterrupt = 3 Return $GUI_RUNDEFMSG EndFunc ;==>_WM_COMMAND Func timerfunc($hWnd, $Msg, $iIDTimer, $dwTime) #forceref $hWnd, $Msg, $iIDTimer, $dwTime Switch _Timer_GetTimerID($iIDTimer) Case $timer if $started = 1 Then Return _Func_1() EndSwitch ; Make sure the flag is cleared EndFunc ;==>timerfunc Edited February 28, 2011 by marko29 Link to comment Share on other sites More sharing options...
PsaltyDS Posted March 1, 2011 Share Posted March 1, 2011 While an event's function is running, additional events are blocked. Event handling functions should never have blocking functions (like MsgBox), Sleep(), or long loops in them. Have your event function change the state of something, like a global flag variable, then your main loop can react to that while other events can be triggered. Even worse, the While/WEnd loop in your _Func_1() function has no exit, and it gets called from timerfunc(), so that function never returns either. Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law Link to comment Share on other sites More sharing options...
wraithdu Posted March 1, 2011 Share Posted March 1, 2011 PsaltyDS beat me to it. Essentially the timer blocks until the execution of the function it is calling is finished. So the solution is to trigger the function in the main loop. I've done it with a dummy control where you can read the state, so you can trigger any number of functions. expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <Timers.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> ; Declare a flag $started = 0 $hGUI = GUICreate("Test", 500, 500) $hButton_1 = GUICtrlCreateButton("Func One", 10, 10, 80, 30) $hButton_2 = GUICtrlCreateButton("Func Two", 10, 50, 80, 30) $hFromTimer = GUICtrlCreateDummy() ; Create a dummy control for the Accelerator to action when pressed $hAccelInterupt = GUICtrlCreateDummy() ; Set an Accelerator key to action the dummy control Dim $AccelKeys[1][2]=[ ["z", $hAccelInterupt] ] GUISetAccelerators($AccelKeys) GUISetState() ; Intercept Windows command messages with out own handler GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND") $timer = _Timer_SetTimer($hGUI, 10000, "timerfunc") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $hButton_1 _Func_1() Case $hButton_2 _Func_2() Case $hFromTimer Switch GUICtrlRead($hFromTimer) Case 1 _Func_1() EndSwitch EndSwitch WEnd Func _Func_1() $started = 1 while 1 ConsoleWrite("Sleeping..." & @CRLF) Sleep(2000) WEnd EndFunc Func _Func_2() ConsoleWrite(">Func 2" & @CRLF) EndFunc Func _WM_COMMAND($hWnd, $Msg, $wParam, $lParam) ; The Func 2 button was pressed so set the flag If BitAND($wParam, 0x0000FFFF) = $hButton_2 Then ConsoleWrite("+BUTTON 2 PRESSED" & @CRLF) ; The dummy control was actioned by the Accelerator key so set the flag If BitAND($wParam, 0x0000FFFF) = $hAccelInterupt Then ConsoleWrite("Accelerated" & @CRLF) Return $GUI_RUNDEFMSG EndFunc ;==>_WM_COMMAND Func timerfunc($hWnd, $Msg, $iIDTimer, $dwTime) #forceref $hWnd, $Msg, $iIDTimer, $dwTime Switch _Timer_GetTimerID($iIDTimer) Case $timer if $started = 1 Then Return ConsoleWrite("Starting _Func_1() from timer..." & @CRLF) GUICtrlSendToDummy($hFromTimer, 1) EndSwitch ; Make sure the flag is cleared EndFunc ;==>timerfunc Link to comment Share on other sites More sharing options...
marko29 Posted March 1, 2011 Author Share Posted March 1, 2011 While an event's function is running, additional events are blocked. Event handling functions should never have blocking functions (like MsgBox), Sleep(), or long loops in them. Have your event function change the state of something, like a global flag variable, then your main loop can react to that while other events can be triggered.Even worse, the While/WEnd loop in your _Func_1() function has no exit, and it gets called from timerfunc(), so that function never returns either.I am thinking if adlibregister would be proper place to do the looping then. btw i didnt add exit as it was just example script to show what i meant(invoking mssg) Link to comment Share on other sites More sharing options...
marko29 Posted March 1, 2011 Author Share Posted March 1, 2011 PsaltyDS beat me to it. Essentially the timer blocks until the execution of the function it is calling is finished. So the solution is to trigger the function in the main loop. I've done it with a dummy control where you can read the state, so you can trigger any number of functions. expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <Timers.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> ; Declare a flag $started = 0 $hGUI = GUICreate("Test", 500, 500) $hButton_1 = GUICtrlCreateButton("Func One", 10, 10, 80, 30) $hButton_2 = GUICtrlCreateButton("Func Two", 10, 50, 80, 30) $hFromTimer = GUICtrlCreateDummy() ; Create a dummy control for the Accelerator to action when pressed $hAccelInterupt = GUICtrlCreateDummy() ; Set an Accelerator key to action the dummy control Dim $AccelKeys[1][2]=[ ["z", $hAccelInterupt] ] GUISetAccelerators($AccelKeys) GUISetState() ; Intercept Windows command messages with out own handler GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND") $timer = _Timer_SetTimer($hGUI, 10000, "timerfunc") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $hButton_1 _Func_1() Case $hButton_2 _Func_2() Case $hFromTimer Switch GUICtrlRead($hFromTimer) Case 1 _Func_1() EndSwitch EndSwitch WEnd Func _Func_1() $started = 1 while 1 ConsoleWrite("Sleeping..." & @CRLF) Sleep(2000) WEnd EndFunc Func _Func_2() ConsoleWrite(">Func 2" & @CRLF) EndFunc Func _WM_COMMAND($hWnd, $Msg, $wParam, $lParam) ; The Func 2 button was pressed so set the flag If BitAND($wParam, 0x0000FFFF) = $hButton_2 Then ConsoleWrite("+BUTTON 2 PRESSED" & @CRLF) ; The dummy control was actioned by the Accelerator key so set the flag If BitAND($wParam, 0x0000FFFF) = $hAccelInterupt Then ConsoleWrite("Accelerated" & @CRLF) Return $GUI_RUNDEFMSG EndFunc ;==>_WM_COMMAND Func timerfunc($hWnd, $Msg, $iIDTimer, $dwTime) #forceref $hWnd, $Msg, $iIDTimer, $dwTime Switch _Timer_GetTimerID($iIDTimer) Case $timer if $started = 1 Then Return ConsoleWrite("Starting _Func_1() from timer..." & @CRLF) GUICtrlSendToDummy($hFromTimer, 1) EndSwitch ; Make sure the flag is cleared EndFunc ;==>timerfunc Thanks a ton! Gonna play with this now Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now