Queso Posted April 5, 2016 Share Posted April 5, 2016 I have a GUI program that communicates with piece of equipment via serial port communications. The problem I'm having is that when the GUI window is moved around on the screen, or even when the user clicks and holds the window, the program pauses. This is a problem because the if the equipment goes for more than a couple of seconds without getting a query from the program it shuts down. So I need a way to either keep the program running while the GUI is moved by the user or a method of making repeated calls to another background program while the _Main() program is paused. However, I'm not sure how to accomplish this. Alternatively, would it be better to write a "new" main function that runs in the background? Then have this new main function create the GUI and monitor when it is being moved. Then when it is moved make calls to the background program? Any help would be greatly appreciated. expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <EditConstants.au3> #include <GuiComboBoxEx.au3> #include <Date.au3> Global $g_hCombo_MODE Global $g_hCombo_CMD Global $g_sCode = "" _Main() Func _Main() Local $GUI_Title = "Temp" Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1) Local $idInput_STATUS = GUICtrlCreateInput(" ", 120, 50, 200, 21,$ES_READONLY) Local $ts = TimerInit() Local $td = TimerDiff($ts) local $sText = "" $g_hCombo_MODE = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST) $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST) GUISetState(@SW_SHOW) GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") While 1 $idMsg = GUIGetMsg() Select Case $idMsg = $GUI_EVENT_CLOSE ExitLoop EndSelect Select Case $g_sCode = "UPDATE MODE" ; Get Item Text _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode = "UPDATE CMD" _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode <> "WAIT" $td = TimerDiff($ts) If $td > 500 Then ;code to ask the status of the instrument including its current mode goes here ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td)) _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0) _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0) $ts = TimerInit() EndIf EndSelect WEnd Exit EndFunc ;==>Main Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $hWndFrom, $iIDFrom, $iCode $hWndFrom = $lParam $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word $iCode = BitShift($wParam, 16) ; Hi Word Switch $hWndFrom Case $g_hCombo_MODE Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE MODE" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch Case $g_hCombo_CMD Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE CMD" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc;==>WM_COMMAND Func Background_Program() ;code to keep communicating with instrument goes here ;For this example just print the time. ConsoleWrite("Running: " & _NowTime() & @LF) Sleep(10) EndFunc;==>Background_Program Link to comment Share on other sites More sharing options...
LarsJ Posted April 6, 2016 Share Posted April 6, 2016 The easy solution is to use a hook procedure: expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <EditConstants.au3> #include <GuiComboBoxEx.au3> #include <Date.au3> #include <WinAPI.au3> Global $g_hCombo_MODE, $idInput_STATUS Global $g_hCombo_CMD Global $g_sCode = "" _Main() Func _Main() Local $GUI_Title = "Temp" Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1) $idInput_STATUS = GUICtrlCreateInput(" ", 120, 50, 200, 21,$ES_READONLY) Local $ts = TimerInit() Local $td = TimerDiff($ts) local $sText = "" $g_hCombo_MODE = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST) $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST) GUISetState(@SW_SHOW) GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; Catch window messages Local $hMessageHandler = DllCallbackRegister( "MessageHandler", "long", "int;wparam;lparam" ) Local $hMessageHook = _WinAPI_SetWindowsHookEx( $WH_GETMESSAGE, DllCallbackGetPtr( $hMessageHandler ), 0, _WinAPI_GetCurrentThreadId() ) While 1 $idMsg = GUIGetMsg() Select Case $idMsg = $GUI_EVENT_CLOSE ExitLoop EndSelect Select Case $g_sCode = "UPDATE MODE" ; Get Item Text _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode = "UPDATE CMD" _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode <> "WAIT" $td = TimerDiff($ts) If $td > 500 Then ;code to ask the status of the instrument including its current mode goes here ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time ;GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td)) _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0) _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0) $ts = TimerInit() EndIf EndSelect WEnd _WinAPI_UnhookWindowsHookEx( $hMessageHook ) Exit EndFunc ;==>Main Func MessageHandler( $nCode, $wParam, $lParam ) Local Static $ts = TimerInit(), $y = 1 Local $td = TimerDiff($ts) If $td > 500 Then ConsoleWrite("Hook message handler: " & $y & @CRLF) GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td)) $ts = TimerInit() $y += 1 EndIf EndFunc Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $hWndFrom, $iIDFrom, $iCode $hWndFrom = $lParam $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word $iCode = BitShift($wParam, 16) ; Hi Word Switch $hWndFrom Case $g_hCombo_MODE Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE MODE" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch Case $g_hCombo_CMD Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE CMD" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc;==>WM_COMMAND Func Background_Program() ;code to keep communicating with instrument goes here ;For this example just print the time. ConsoleWrite("Running: " & _NowTime() & @LF) Sleep(10) EndFunc;==>Background_Program Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
UEZ Posted April 6, 2016 Share Posted April 6, 2016 (edited) You can use also the SetTimer function: expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <EditConstants.au3> #include <GuiComboBoxEx.au3> #include <Date.au3> Global $g_hCombo_MODE Global $g_hCombo_CMD Global $g_sCode = "" _Main() Func _Main() Local $GUI_Title = "Temp" Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1) Local $idInput_STATUS = GUICtrlCreateInput(" ", 120, 50, 200, 21,$ES_READONLY) Local $ts = TimerInit() Local $td = TimerDiff($ts) local $sText = "" $g_hCombo_MODE = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST) $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST) GUISetState(@SW_SHOW) GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") GUIRegisterMsg($WM_TIMER, "Background_Program") ;$WM_TIMER = 0x0113 Local $iTimer = 100 ;100 ms DllCall("user32.dll", "int", "SetTimer", "hwnd", $hGUI, "int", 0, "int", $iTimer, "int", 0) While 1 $idMsg = GUIGetMsg() Select Case $idMsg = $GUI_EVENT_CLOSE GUIRegisterMsg($WM_TIMER, "") ExitLoop EndSelect Select Case $g_sCode = "UPDATE MODE" ; Get Item Text _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode = "UPDATE CMD" _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode <> "WAIT" $td = TimerDiff($ts) If $td > 500 Then ;code to ask the status of the instrument including its current mode goes here ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td)) _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0) _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0) $ts = TimerInit() EndIf EndSelect WEnd Exit EndFunc ;==>Main Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $hWndFrom, $iIDFrom, $iCode $hWndFrom = $lParam $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word $iCode = BitShift($wParam, 16) ; Hi Word Switch $hWndFrom Case $g_hCombo_MODE Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE MODE" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch Case $g_hCombo_CMD Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE CMD" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc;==>WM_COMMAND Func Background_Program() ;code to keep communicating with instrument goes here ;For this example just print the time. ConsoleWrite("Running: " & _NowTime() & @LF) ;Sleep(10) EndFunc;==>Background_Program @LarsJ: learned something new! Thx. Edited April 6, 2016 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Queso Posted April 6, 2016 Author Share Posted April 6, 2016 Thank you both @LarsJ and @UEZ for your insights and taking the time to respond. (I kind of figured it was going to take the use of DLL calls.) However there is still one issue. The background program is called repeatedly not only when there is a pause in the execution of the main while loop. The reason this is an issue, is when I add the serial port communication to Background_Program the commands that it issues start to conflict with the serial commands coming from the main while loop. Is there a way to make it so that the program or at least the ConsoleWrite command is only executed if the if the main while loop hasn't run in a few seconds? Link to comment Share on other sites More sharing options...
UEZ Posted April 7, 2016 Share Posted April 7, 2016 7 hours ago, Queso said: Is there a way to make it so that the program or at least the ConsoleWrite command is only executed if the if the main while loop hasn't run in a few seconds? Well, a loop is a loop that means that your main loop runs continuously. You have to redesign the main loop either to run the serial port communication or console write function. Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Queso Posted April 11, 2016 Author Share Posted April 11, 2016 Thanks, @UEZ. I think that rewriting the main loop is probably the best way to go. However I was able to get it to work using @LarsJ example. Basically when the GUI window is moved $lParam is decreased by 2356. So if I check $lParam every time the message handler is called, I can have it send a dummie serial commands to the instrument in order to keep communication open whenever ($lParam == $lParam_init - 2356) and do nothing otherwise so that my normal communication can continue. I'll have to try it with the full program, but I think this will offer at least a short term solution. Thanks again both of you for your help. expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <EditConstants.au3> #include <GuiComboBoxEx.au3> #include <Date.au3> #include <WinAPI.au3> Global $g_hCombo_MODE, $idInput_STATUS Global $g_hCombo_CMD Global $g_sCode = "" Global $lParam_init = 0 _Main() Func _Main() Local $GUI_Title = "Temp" Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1) $idInput_STATUS = GUICtrlCreateInput(" ", 120, 50, 200, 21,$ES_READONLY) Local $ts = TimerInit() Local $td = TimerDiff($ts) local $sText = "" $g_hCombo_MODE = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST) $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST) GUISetState(@SW_SHOW) GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; Catch window messages Local $hMessageHandler = DllCallbackRegister( "MessageHandler", "long", "int;wparam;lparam" ) Local $hMessageHook = _WinAPI_SetWindowsHookEx( $WH_GETMESSAGE, DllCallbackGetPtr( $hMessageHandler ), 0, _WinAPI_GetCurrentThreadId() ) While 1 $idMsg = GUIGetMsg() Select Case $idMsg = $GUI_EVENT_CLOSE ExitLoop EndSelect Select Case $g_sCode = "UPDATE MODE" ; Get Item Text _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode = "UPDATE CMD" _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText) GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText) ;Code to send command to instrument goes here $g_sCode = "" $ts = TimerInit() Case $g_sCode <> "WAIT" $td = TimerDiff($ts) If $td > 500 Then ;code to ask the status of the instrument including its current mode goes here ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time ;GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td)) _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0) _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0) $ts = TimerInit() EndIf EndSelect WEnd _WinAPI_UnhookWindowsHookEx( $hMessageHook ) Exit EndFunc ;==>Main Func MessageHandler( $nCode, $wParam, $lParam ) Local Static $ts = TimerInit(), $y = 1 Local $td = TimerDiff($ts) ;Run frst time through the loop to get the nominal value of $lParm (There is probably a better way to to do this. If $lParam_init = 0 Then $lParam_init = $lParam If $td > 500 Then If $lParam == $lParam_init - 2356 Then ConsoleWrite("Hook message handler: " & $y & " : " & $lParam_init & " : " & $lParam & " : " & $lParam_init -2356 & @CRLF) EndIf GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td)) $ts = TimerInit() $y += 1 EndIf EndFunc Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $hWndFrom, $iIDFrom, $iCode $hWndFrom = $lParam $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word $iCode = BitShift($wParam, 16) ; Hi Word Switch $hWndFrom Case $g_hCombo_MODE Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE MODE" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch Case $g_hCombo_CMD Switch $iCode Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed $g_sCode = "UPDATE CMD" Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible $g_sCode = "WAIT" EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc;==>WM_COMMAND Func Background_Program() ;code to keep communicating with instrument goes here ;For this example just print the time. ConsoleWrite("Running: " & _NowTime() & @LF) Sleep(10) EndFunc;==>Background_Program 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