gspot Posted June 3, 2014 Share Posted June 3, 2014 (edited) Hi , How can i keep my GUI with buttons in a responsive state even if script is waiting for a window? Example: Click in "Wait Excel" (waits for a Excel file to exist). The buttons "Stop" and "msgbox" dont work because is waiting for excel... Its possible to make them work? Thanks in advance #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Form1", 623, 446, 192, 114) $Button1 = GUICtrlCreateButton("Wait excell", 192, 64, 105, 49) $Button2 = GUICtrlCreateButton("Stop", 192, 136, 105, 49) $Button3 = GUICtrlCreateButton("msgbox", 192, 208, 105, 49) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button2 Exit Case $Button1 WinWait("Microsoft Excel", "GSO") Case $Button3 MsgBox(0, "test", "ABC") EndSwitch WEnd Edited June 3, 2014 by gspot Link to comment Share on other sites More sharing options...
rodent1 Posted June 3, 2014 Share Posted June 3, 2014 You could use the timeout parameter of Winwait() and verify the return value of the function Winwait(). If the call is successful, you go on with your script. If it's not, set a constant to true when the process exits WinWait(). Then when coming back on top of the while loop, check the constant value. If it's true, check if $nMsg is same as $Button3. If it is, run the $Button3 command (in your sample, display a msgbox). Then set $nMsg back to $Button1. In short, replace your while loop with this: Local $Flag = False While 1 $nMsg = GUIGetMsg() if $Flag = True Then if $nMsg = $Button3 Then MsgBox(0, "test", "ABC") EndIf $nMsg = $Button1 EndIf Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button2 Exit Case $Button1 $Flag = WinWait("Microsoft Excel", "GSO", 1) = 0 ; will set $Flag to true if winwait did not find excel, else false Case $Button3 MsgBox(0, "test", "ABC") EndSwitch WEnd Link to comment Share on other sites More sharing options...
gspot Posted June 3, 2014 Author Share Posted June 3, 2014 You could use the timeout parameter of Winwait() and verify the return value of the function Winwait(). If the call is successful, you go on with your script. If it's not, set a constant to true when the process exits WinWait(). Then when coming back on top of the while loop, check the constant value. If it's true, check if $nMsg is same as $Button3. If it is, run the $Button3 command (in your sample, display a msgbox). Then set $nMsg back to $Button1. In short, replace your while loop with this: Local $Flag = False While 1 $nMsg = GUIGetMsg() if $Flag = True Then if $nMsg = $Button3 Then MsgBox(0, "test", "ABC") EndIf $nMsg = $Button1 EndIf Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button2 Exit Case $Button1 $Flag = WinWait("Microsoft Excel", "GSO", 1) = 0 ; will set $Flag to true if winwait did not find excel, else false Case $Button3 MsgBox(0, "test", "ABC") EndSwitch WEnd Didnt work for me. GUI doesn't respond after clicking "Wait Excel"... Link to comment Share on other sites More sharing options...
jdelaney Posted June 3, 2014 Share Posted June 3, 2014 (edited) You can "run" (NOT runwait) a second, parallel process (another script), durring the loop, wait for the process to end, and then get it's return value...forum search _Parallel_CreateProcess..._processexistsbyhandle. That way, your gui will always respond, and you can get the return of your function. Edited June 3, 2014 by jdelaney IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window. Link to comment Share on other sites More sharing options...
gspot Posted June 4, 2014 Author Share Posted June 4, 2014 You can "run" (NOT runwait) a second, parallel process (another script), durring the loop, wait for the process to end, and then get it's return value...forum search _Parallel_CreateProcess..._processexistsbyhandle. That way, your gui will always respond, and you can get the return of your function. I think thats a little advanced for me, can you give a simple example or where i can see some examples? Thanks for the help Link to comment Share on other sites More sharing options...
gspot Posted June 5, 2014 Author Share Posted June 5, 2014 Anybody? Can some one give a simple example? thanks Link to comment Share on other sites More sharing options...
Geir1983 Posted June 5, 2014 Share Posted June 5, 2014 WinWait Pauses execution of the script until the requested window exists. Run Runs an external program. The WinWait function intentionally pauses your script, why not just use Run as this seems what you want? Link to comment Share on other sites More sharing options...
Solution jdelaney Posted June 5, 2014 Solution Share Posted June 5, 2014 (edited) Here is an example of the gui always being responsive: expandcollapse popup#include <GUIConstantsEx.au3> #include <WinAPI.au3> #include <Constants.au3> #include <WindowsConstants.au3> $aProcess = "" $iProcessesCreated = 1 $iMsgBoxCreated = 1 $iMsgBox = "" $Form1 = GUICreate("Form1", 623, 446, 192, 114) $Button1 = GUICtrlCreateButton("Wait excell", 192, 64, 105, 49) $Button2 = GUICtrlCreateButton("Stop", 192, 136, 105, 49) $Button3 = GUICtrlCreateButton("msgbox", 192, 208, 105, 49) GUISetState(@SW_SHOW) Local $Flag = False While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE If IsArray($aProcess) Then ConsoleWrite("Killing prior task that was initiated" & @CRLF) ProcessClose($aProcess[0]) EndIf If $iMsgBox Then ProcessClose($iMsgBox) Exit Case $Button2 If IsArray($aProcess) Then ConsoleWrite("Killing prior task that was initiated" & @CRLF) ProcessClose($aProcess[0]) EndIf If $iMsgBox Then ProcessClose($iMsgBox) Exit Case $Button1 $iCounter = 1 If IsArray($aProcess) Then ConsoleWrite("Killing prior task that was initiated" & @CRLF) ProcessClose($aProcess[0]) EndIf $sCommand = 'AutoIt3.exe /ErrorStdOut /AutoIt3ExecuteLine "Exit (Sleep(5000))+' & $iProcessesCreated & '"' $iProcessesCreated+=1 $aProcess = _Parallel_CreateProcess($sCommand) Case $Button3 If $iMsgBox Then ProcessClose($iMsgBox) $sCommand = 'AutoIt3.exe /ErrorStdOut /AutoIt3ExecuteLine "MsgBox(0, ''test'', ''ABC...Initiated=[' & $iMsgBoxCreated & ']x'')"' $iMsgBoxCreated += 1 $iMsgBox = Run($sCommand) EndSwitch If IsArray($aProcess) Then $iCounter+=1 If IsInt($iCounter/50) Then ConsoleWrite("Your command is still running" & @CRLF) EndIf If Not _ProcessExistsByHandle($aProcess[1],10) Then $iReturnOfResult=@extended ConsoleWrite("Returned=" & $iReturnOfResult & @CRLF) $aProcess = 0 EndIf EndIf Sleep (10) WEnd Exit Func _Parallel_CreateProcess($sCommand, $sWrkDir="", $iShow=@SW_MINIMIZE, $iOpts=0) ; #FUNCTION# ==================================================================================================================== ; Name ..........: _Parallel_CreateProcess ; Description ...: Launch a new process. ; Syntax ........: _Parallel_CreateProcess($sCommand, $sWrkDir, $iShow, $iOpts) ; Parameters ....: $sCommand - Command line including parameters. ; $sWrkDir - Working directory. Default = "". ; $iShow - Initial state of any application window, any of the @SW_ macros. ; $iOpts - Options 0x10 or 0x10000 from internal Run() command, BitOR'd. ; Return values .: Success - A two element array: ; [0] - PID ; [1] - process handle (MUST be closed when finished with it) ; Failure - Sets @error = 1 and returns 0 as PID and handle ; Author ........: Erik Pilsits ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== ; use options provided by internal Run() command for consistent usage ; but only supports 0x10 and 0x10000 ; Local $aRet[2] = [0, 0] Local $sSTARTUP = DllStructCreate($tagSTARTUPINFO) Local $sPROCINFO = DllStructCreate($tagPROCESS_INFORMATION) DllStructSetData($sSTARTUP, "Size", DllStructGetSize($sSTARTUP)) DllStructSetData($sSTARTUP, "Flags", $STARTF_USESHOWWINDOW) DllStructSetData($sSTARTUP, "ShowWindow", $iShow) ; ; check options If BitAND($iOpts, 0x10) = 0x10 Then ; inherit parent stdio handles DllStructSetData($sSTARTUP, "Flags", BitOR($STARTF_USESHOWWINDOW, $STARTF_USESTDHANDLES)) DllStructSetData($sSTARTUP, "StdInput", _WinAPI_GetStdHandle(0)) DllStructSetData($sSTARTUP, "StdOutput", _WinAPI_GetStdHandle(1)) DllStructSetData($sSTARTUP, "StdError", _WinAPI_GetStdHandle(2)) EndIf Local $dwCreationFlags = 0 If BitAND($iOpts, 0x10000) = 0x10000 Then ; CREATE_NEW_CONSOLE = 0x10 $dwCreationFlags = 0x10 EndIf ; check working dir Local $sWrkDirType = "wstr" If $sWrkDir = "" Then $sWrkDirType = "ptr" $sWrkDir = 0 EndIf ; Local $ret = DllCall("kernel32.dll", "bool", "CreateProcessW", "ptr", 0, "wstr", $sCommand, "ptr", 0, "ptr", 0, "bool", 0, _ "dword", $dwCreationFlags, "ptr", 0, $sWrkDirType, $sWrkDir, "struct*", $sSTARTUP, "struct*", $sPROCINFO) If @error Or Not $ret[0] Then Return SetError(1, 0, $aRet) ; ; close unused thread handle _WinAPI_CloseHandle(DllStructGetData($sPROCINFO, "hThread")) ; ; return array of info, [0] = PID, [1] = process handle $aRet[0] = DllStructGetData($sPROCINFO, "ProcessID") $aRet[1] = DllStructGetData($sPROCINFO, "hProcess") Return SetError(0, 0, $aRet) EndFunc ;==>_Parallel_CreateProcess Func _ProcessExistsByHandle($hProc,$iTimeOutMilSec) ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ProcessExistsByHandle ; Description ...: Check if a process exists by handle. ; Syntax ........: _ProcessExistsByHandle($hProc) ; Parameters ....: $hProc - Open handle to a process, for example from a call to OpenProcess. ; Return values .: Success - 0 if process has ended, 1 if it still exists ; @extended contains the exit code ; Failure - 0 and sets @error ; Author ........: Erik Pilsits ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== ; there was an error creating the process If Not $hProc Then Return SetError(1, 0, 0) ; Local $iExit = DllCall("kernel32.dll", "bool", "GetExitCodeProcess", "handle", $hProc, "dword*", -1) If @error Or (Not $iExit[0]) Then ; error Return SetError(1, 0, 0) ElseIf $iExit[2] = 259 Then ; process STILL_ACTIVE ; extra check if process used STILL_ACTIVE as a valid exit code, $WAIT_OBJECT_0 If _WinAPI_WaitForSingleObject($hProc, $iTimeOutMilSec) = 0 Then If $iExit[2] = 259 Then _ProcessExistsByHandle($hProc,$iTimeOutMilSec) Return SetExtended(@extended,0) Else Return SetExtended($iExit[2], 0) EndIf Else Return 1 EndIf Else ; process does not exist, return exit code in @extended Return SetExtended($iExit[2], 0) EndIf EndFunc ;==>_ProcessExistsByHandle Edited June 5, 2014 by jdelaney gspot 1 IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window. Link to comment Share on other sites More sharing options...
dragan Posted June 5, 2014 Share Posted June 5, 2014 Personally, I would have done it like this: expandcollapse popup#include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <GuiMenu.au3> #include <WinAPI.au3> Global $Counter = 0; Global $isCounting = False; Global $WaitExcel = False; Global $WaitExcelTimeOut = 0; Global $ExcelTimeNow = null; $Form1 = GUICreate("Count 1 to 100", 250, 240) $Button1 = GUICtrlCreateButton("Start", 15, 15, 75, 25) $Label1 = GUICtrlCreateLabel("0", 135, 16, 40, 17) $Button2 = GUICtrlCreateButton("Stop", 15, 55, 75, 25) $Button3 = GUICtrlCreateButton("Reset", 15, 95, 75, 25) $Button4 = GUICtrlCreateButton("Start Excel", 15, 155, 75, 25) $Button5 = GUICtrlCreateButton("Stop waiting Excel", 15, 195, 100, 25) GUISetState(@SW_SHOW) GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND") While 1 Sleep(10); ;----- loop that can be broken: ---------- if ($isCounting AND $Counter < 100) Then While $Counter < 100 AND $isCounting $Counter += 1 GUICtrlSetData($Label1, $Counter) Sleep(100) WEnd $isCounting = False; EndIf ;----------------------------------------- ;----------------------------------------- if ($WaitExcel) Then While 1 if WinExists("Microsoft Excel", "") Then MsgBox(0, "Success", "Excel is up and running!") ExitLoop EndIf if NOT $WaitExcel Then MsgBox(0, "Canceled", "You are no longer waiting for excel!") ExitLoop EndIf if $ExcelTimeNow <> null AND $WaitExcelTimeOut > 0 Then if (TimerDiff($ExcelTimeNow) >= $WaitExcelTimeOut*1000) then MsgBox(0, "Timed out", "You are no longer waiting for excel!" & @CRLF & "Timed out.") ExitLoop EndIf EndIf Sleep(10); WEnd $WaitExcel = False; EndIf ;----------------------------------------- WEnd Func WM_SYSCOMMAND($hWnd, $iMsg, $WParam, $LParam) Switch $hWnd Case $Form1 Switch $WParam Case $SC_CLOSE ;X button in the GUI form Exit; EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam) Local $nID = BitAND($iwParam, 0x0000FFFF) #forceref $hWnd, $iMsg, $iwParam, $ilParam $iCode = _WinAPI_HiWord($iwParam) Switch $nID Case $Button1 $isCounting = True; Case $Button2 $isCounting = False; Case $Button3 $Counter = 0; GUICtrlSetData($Label1, $Counter) Case $Button4 $WaitExcelTimeOut = 30; wait for 30 seconds. $ExcelTimeNow = TimerInit(); ShellExecute("excel.exe"); $WaitExcel = True; Case $Button5 $WaitExcel = False; EndSwitch Return $GUI_RUNDEFMSG EndFunc gspot 1 Link to comment Share on other sites More sharing options...
jdelaney Posted June 5, 2014 Share Posted June 5, 2014 (edited) I like how you break out the gui control loop. You should add a little more, such as waiting for YOUR instance of excel being opened, and not just ANY instance of a window with "Microsoft Excel" being open. Edited June 5, 2014 by jdelaney IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window. Link to comment Share on other sites More sharing options...
gspot Posted June 6, 2014 Author Share Posted June 6, 2014 Thanks for the answers, i dont fully understand the code, but i will study him for shure. Thanks again. 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