How to Winwait for two windows simultaneously in AutoIt? - windows

I would like to know if its possible to WinWaitActive for WindowWithThisTitle and WindowWithThatTitle at the same time. I'm executing a command and there could be a window telling me that the connection failed or a user/pass dialog coming up.
Is there another way doing it as this?
WinWaitActive("Title1", "", 5)
If(WinExists("Title1")) Then
MsgBox(0, "", "Do something")
Else
If(WinExists("Title2")) Then
MsgBox(0, "", "Do something else")
EndIf
EndIf
Because I don't want to have the timeout which could be more than 15 seconds.

A simpler solution might be to use a REGEX title in your WinWaitActive as defined here
You would then have something like this:
$hWnd = WinWaitActive("[REGEXPTITLE:(WindowWithThisTitle|WindowWithThatTitle)]")
If WinGetTitle($hWnd) = "WindowWithThisTitle" then
DoSomething()
Else
DoSomethingElse()
EndIf

How about something like this.
$stillLooking = True
While $stillLooking
$activeWindowTitle = WinGetTitle(WinActive(""))
If $activeWindowTitle == "Title1" Then
MsgBox(0, "", "Do something")
$stillLooking = False
ElseIf $activeWindowTitle == "Title2" Then
MsgBox(0, "", "Do something else")
$stillLooking = False
EndIf
sleep(5)
WEnd
Because I don't want to have the
timeout which could be more than 15
seconds.
WinWaitActive() doesn't have a timeout unless you specify one. You gave it a five second timeout but you could leave that off and it would wait forever.

You can use this Functions for two windows ..
; #FUNCTION# ====================================================================================================================
; Name...........: _2WinWait
; Description ...: Wait For Tow Windows .
; Syntax.........: _2WinWait ($FirstTitle,$SecondTitle,[$FirstText = "" ,[$SecondText = ""]] )
; Parameters ....: $FirstTitle - Title Of First Wondow
; $SecondTitle - Title Of Second Wondow
; $FirstText - Text Of First Wondow
; $SecondText - Text Of Second Wondow
; Return values .: Success - None
; Failure - Returns a 0 => If Your Titles Is Wrong
; Author ........: Ashalshaikh : Ahmad Alshaikh
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; No
; ===============================================================================================================================
Func _2WinWait ($FirstTitle,$SecondTitle,$FirstText = "" ,$SecondText = "" )
If $FirstTitle = "" Or $SecondTitle = "" Then
Return 0
Else
Do
Until WinExists ($FirstTitle,$FirstText) Or WinExists ($SecondTitle,$SecondText)
EndIf
EndFunc
; #FUNCTION# ====================================================================================================================
; Name...........: _2WinWait_Any
; Description ...: Wait For Tow Windows And Return Any Window Id Exists .
; Syntax.........: _2WinWait_Any ($FirstTitle,$SecondTitle,[$FirstText = "" ,[$SecondText = ""]] )
; Parameters ....: $FirstTitle - Title Of First Wondow
; $SecondTitle - Title Of Second Wondow
; $FirstText - Text Of First Wondow
; $SecondText - Text Of Second Wondow
; Return values .: Success - Number Of Window ==> 1= First Window , 2= Second Window
; Failure - Returns a 0 => If Your Titles Is Wrong
; Author ........: Ashalshaikh : Ahmad Alshaikh
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; No
; ===============================================================================================================================
Func _2WinWait_Any ($FirstTitle,$SecondTitle,$FirstText = "" ,$SecondText = "" )
If $FirstTitle = "" Or $SecondTitle = "" Then
Return 0
Else
Do
Until WinExists ($FirstTitle,$FirstText) Or WinExists ($SecondTitle,$SecondText)
If WinExists ($FirstTitle,$FirstTexit) Then
Return 1
Else
Return 2
EndIf
EndIf
EndFunc
for more with examples

I'm fairly new to autoit and the programming world in general and I had this same dilemma. Luckily I figured out a straight fwd way to do it:
Do
$var1 = 0
If WinGetState("Document Reference","") Then
$var1 = 1
ElseIf WinGetState("Customer Search","") Then
$var1 = 1
EndIf
Until $var1 = 1
So it'll stay in the loop until it finds the window and sets $var1 to 1. There's probably easier ways (I'm sure developers are gasping at this) but this is straight fwd enough for me.

You can create an infinite while loop with if statements in there:
#include <MsgBoxConstants.au3>
Example()
Func Example()
While 1
; Test if the window exists and display the results.
If WinExists("Windows Security") Then
Local $hWnd = WinWaitActive("Windows Security", "", 2000)
ControlSetText($hWnd, "", "[CLASS:Edit; INSTANCE:1]", "hel233")
ControlClick("Windows Security","","[CLASS:Button; INSTANCE:2]")
Sleep(5000)
EndIf
; Test if the window exists and display the results.
If WinExists("Spread the Word") Then
'The line below will wait until the window is active, but we don't need that
'Local $hWnd = WinWaitActive("Spread the Word", "", 2000)
WinClose("Spread the Word")
Sleep(5000)
EndIf
wend
EndFunc

Related

Looping through WinList() result takes much time

I get a list of open windows and check if it contains a certain title. It is working but takes more than 10 seconds. Why does it take so long, what is wrong with my code?
Looks like WinList() doesn't list only visible windows.
$title = 0
$begintime = TimerInit()
MsgBox($MB_OK, "Timer", "Timer inicialized")
While $title = 0
$aList = WinList()
For $x = 1 To $aList[0][0]
;Check if a window with this title exists.
if $aList[$x][0] = "WindowTitle" Then
If $lastruntitle = "WindowTitle" Then
$title = 1
ExitLoop(2)
Else
SendMail4()
$lastruntitle = "WindowTitle"
$title = 1
ExitLoop(2)
EndIf
EndIf
Next
WEnd
Simple solution for your task is:
#include <Array.au3>
While 1
$aList = WinList()
_ArraySearch($aList, "WindowTitle", 0, 0, 0, 0, 1, 0)
If Not #error Then
MsgBox(0,"","Window found!")
Exit
EndIf
Sleep(100)
WEnd

Refresh a GUI using AutoIt

I am making AutoIt code and one of the items on the GUI needs to be updated every few seconds, and I can seem to get it to do it. To make it simple I have written some code that shows the problem:
$num = 0
GUICreate("Example")
$Pic1 = GUICtrlCreateLabel($num, 10, 10)
GUISetState()
While 1
sleep(1000)
$num = $num + "1"
WEnd
If the code was working then the number would change, but it does not. How do I make it refresh?
The number is updating, but your data is not. Plus, you are mixing integers with strings.
Luckily AutoIt converts them automatically. But take care, because you will have problems in other programming languages.
Here you go:
Local $num = 0
Local $hGUI = GUICreate("Example")
Local $Pic1 = GUICtrlCreateLabel($num, 10, 10)
GUISetState()
Local $hTimer = TimerInit()
While 1
;sleep(1000)
If TimerDiff($hTimer) > 1000 Then
$num += 1
GUICtrlSetData($Pic1, $num)
$hTimer = TimerInit()
EndIf
If GUIGetMsg() = -3 Then ExitLoop
WEnd
P.S.: Avoid using sleep in these situations while they will pause your script.
This is easily done with AdLibRegister passing the function name and then 1000 milliseconds (1 second).
Local $num = 0
Local $hGUI = GUICreate("Example")
Local $Pic1 = GUICtrlCreateLabel($num, 10, 10)
Local $msg
GUISetState()
AdLibRegister("addOne", 1000)
While 1
$msg = GUIGetMsg()
Switch $msg
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Func addOne ()
$num += 1
GUICtrlSetData($Pic1, $num)
EndFunc
You need to set the new data in the GUI using GUICtrlSetData. Simply modify your loop like this:
While 1
sleep(1000)
$num += 1
GUICtrlSetData($Pic1, $num)
WEnd
Note that I removed the double-quotes so that AutoIt handles the values as integers.

Detecting system shutdown or logoff

How can I detect when a system is shutting down or logging off with AutoIt?
I need to run a function if the computer is shutdown or logged off while my script is still running.
You need to handle the Message WM_QUERYENDSESSION
Sample Code:
; Define Windows Message Codes
$WM_QUERYENDSESSION = 0x11
; Define Callback Parameter Codes
$ENDSESSION_CLOSEAPP = 0x00000001
$ENDSESSION_CRITICAL = 0x40000000
$ENDSESSION_LOGOFF = 0x80000000
; Register a Callback on the Message to the Function "onShutDown"
GUIRegisterMsg($WM_QUERYENDSESSION, "onShutDown")
; #FUNCTION# ========================================================
; Name...........: onShutDown Example Function
; Description ...: Application receives the WM_QUERYENDSESSION message
;
; Parameters ....:
; $hWndGUI - A handle to the window
; $MsgID - The WM_QUERYENDSESSION identifier
; $wParam - This parameter is reserved for future use
; $lParam - This parameter can be one or more of the following values.
; |0 - The system is shutting down or restarting
; (it is not possible to determine which event is occurring)
; |$ENDSESSION_CLOSEAPP - Application is using a ressource or file that needs to be freed
; |$ENDSESSION_CRITICAL - Application is forced to shut down
; |$ENDSESSION_LOGOFF - The user is logging off
;
; Return values .:
; |True - Allow to Shutdown
; |False - Prevent Shutdown
; Remarks .......: Applications should respect the user's intentions and return TRUE. By default any application returns **TRUE** for this message.
; If shutting down would corrupt the system or media that is being burned, the application can return **FALSE**.
; However, it is good practice to respect the user's actions.
;
Func onShutDown($hWndGUI, $MsgID, $wParam, $lParam)
Return True ; allow Shutdown ( or return "False" to prevent Shutdown )
EndFunc
Also See : List of Windows Message Codes
You can implement OnAutoItExitRegister() in such a way that you can assume the PC is shutting down.
OnAutoItExitRegister("DetectShutdown")
GUICreate("My GUI") ; will create a dialog box that when displayed is centered
GUISetState(#SW_SHOW) ; will display an empty dialog box
; Run the GUI until the dialog is closed
While True
$msg = GUIGetMsg()
If $msg = $GUI_EVENT_CLOSE Then
OnAutoItExitUnRegister("DetectShutdown")
Exit
EndIf
WEnd
Func DetectShutdown()
MsgBox(0, "", "Shutdown Detected!")
EndFunc
How can I detect when a system is shutting down or logging off with AutoIt?
As per Documentation - Function Reference - OnAutoItExitRegister() :
The mode of exit can be retrieved with #exitMethod.
Also detects user logoff and Windows shutdown.
I need to run a function if the computer is shutdown or logged off while my script is still running.
Example (determination of-, and reaction to exit methods):
#include <AutoItConstants.au3>; #exitMethod constants.
Global Enum $EXIT_OK, _
$EXIT_ONAUTOITEXITREGISTER, _
$EXIT_HOTKEYSET
Global Const $g_iDelayMain = 250
Global Const $g_iDelayExit = 1000 * 5
Global Const $g_sKeyExit = '{ESC}'
Global Const $g_sConsole = '%s-%s-%s %s:%s:%s.%s - #exitCode = %i (%s) #exitMethod = %i (%s)\n'
Global Const $g_aExit = [ _
'OK', _
'OnAutoItExitRegister() failed', _
'HotKeySet() failed' _
]
Global Const $g_aMethod = [ _
'end of script reached', _
'Exit function executed', _
'systray exit function activated', _
'Windows logoff', _
'Windows shutdown' _
]
Global $g_bStateExit = False
Main()
Func Main()
If Not OnAutoItExitRegister('_ReportExit') Then Exit $EXIT_ONAUTOITEXITREGISTER
If Not HotKeySet($g_sKeyExit, 'SetStateExit') Then Exit $EXIT_HOTKEYSET
While Not $g_bStateExit
Sleep($g_iDelayMain)
WEnd
Exit $EXIT_OK
EndFunc
Func _ReportExit()
Local Const $sLine = StringFormat($g_sConsole, _
#YEAR, #MON, #MDAY, #HOUR, #MIN, #SEC, #MSEC, _
#exitCode, $g_aExit[#exitCode], _
#exitMethod, $g_aMethod[#exitMethod] _
)
ConsoleWrite($sLine)
Sleep($g_iDelayExit)
Switch #exitMethod
; Case $EXITCLOSE_NORMAL
; Your code here.
; Case $EXITCLOSE_BYEXIT
; Your code here.
; Case $EXITCLOSE_BYCLICK
; Your code here.
Case $EXITCLOSE_BYLOGOFF
; Your code here.
Case $EXITCLOSE_BYSHUTDOWN
; Your code here.
EndSwitch
EndFunc
Func SetStateExit()
$g_bStateExit = True
EndFunc

Button = Website Link in AutoIT

I have made a button in AutoIT for this program we are making for work we will call it $okmystery and I want $okmystery to like to my company website. Here is a snippet of the code I have so far:
Dim $msg
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $okbutton
; Minimize Current Window
WinSetState( $WINTITLE, "", #SW_MINIMIZE)
While Not BitAND(WinGetState($WINTITLE, ""), 16)
sleep( 250 )
WEnd
; Take Screen Shots and Logs
ScreenShotAndLogs()
; Compress Artifacts
If FileExists( $ZIPFILEPATH ) Then FileDelete( $ZIPFILEPATH )
_Zip_Create( $ZIPFILEPATH )
_Zip_AddFolderContents( $ZIPFILEPATH, $OUTPUTROOT )
DeleteOriginals()
; Restore main window
WinSetState( $WINTITLE, "", #SW_RESTORE)
;------------ Screen Shot
Case $msg = $okshot
; Minimize Current Window
WinSetState( $WINTITLE, "", #SW_MINIMIZE)
While Not BitAND(WinGetState($WINTITLE, ""), 16)
sleep( 250 )
WEnd
ScreenShot()
; Restore main window
WinSetState( $WINTITLE, "", #SW_RESTORE)
;----------------------------------
$okmystery = ShellExecute ("basic")
Run("Http://www.IT-Networks.org")
Case Default
; Do Nothing
EndSelect
WEnd
Exit( 0 )
It looks like you need to change the "$okmystery" case statement to match the other case statements (if those are all working like they're supposed to).
You can then try to ShellExecute() the url.
Case $msg = $okmystery
ShellExecute("Http://www.IT-Networks.org")
Here's a working example of a GUI with a button that opens your company website in your default web browser:
#include <GUIConstantsEx.au3>
Global $Button_1, $msg
GUICreate("Test GUI Button")
$okmystery = GUICtrlCreateButton("okmystery Button", 10, 30, 100)
GUISetState()
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $okmystery
ShellExecute("Http://www.IT-Networks.org")
EndSelect
WEnd

Best way to wrap rsync progress in a gui?

I use rsync to synchronize files to Windows clients in a server agnostic way. What methods are available to send the progress of rsync to the parent process for display in a gui progress bar?
I imagine two or three choices exist. (1) Watch STDOUT (2) Watch rsync.exe log file, similar to unix tail (3) Watch rsync console output in memory.
Which one is best/preferred?
For this type of tasks, I use my own AutoIt script (freeware, Windows only). The script redirects the standard output into a graphical window, displaying it with the ability to scroll back, etc (very useful in long processes like XCOPYs / PKZIPs to check if any error did happen).
I use AutoIt because it's free, very easy to use, and can compile quickly into an .EXE. I think it's an excellent alternative to a complete programming language for this type of tasks. The downside is that it's for Windows only.
$sCmd = "DIR E:\*.AU3 /S" ; Test command
$nAutoTimeout = 10 ; Time in seconds to close window after finish
$nDeskPct = 60 ; % of desktop size (if percent)
; $nHeight = 480 ; height/width of the main window (if fixed)
; $nWidth = 480
$sTitRun = "Executing process. Wait...." ;
$sTitDone = "Process done" ;
$sSound = #WindowsDir & "\Media\Ding.wav" ; End Sound
$sButRun = "Cancel" ; Caption of "Exec" button
$sButDone = "Close" ; Caption of "Close" button
#include <GUIConstants.au3>
#include <Constants.au3>
#Include <GuiList.au3>
Opt("GUIOnEventMode", 1)
if $nDeskPct > 0 Then
$nHeight = #DesktopHeight * ($nDeskPct / 100)
$nWidth = #DesktopWidth * ($nDeskPct / 100)
EndIf
If $CmdLine[0] > 0 Then
$sCmd = ""
For $nCmd = 1 To $CmdLine[0]
$sCmd = $sCmd & " " & $CmdLine[$nCmd]
Next
; MsgBox (1,"",$sCmd)
EndIf
; AutoItSetOption("GUIDataSeparatorChar", Chr(13)+Chr(10))
$nForm = GUICreate($sTitRun, $nWidth, $nHeight)
GUISetOnEvent($GUI_EVENT_CLOSE, "CloseForm")
$nList = GUICtrlCreateList ("", 10, 10, $nWidth - 20, $nHeight - 50, $WS_BORDER + $WS_VSCROLL)
GUICtrlSetFont (-1, 9, 0, 0, "Courier New")
$nClose = GUICtrlCreateButton ($sButRun, $nWidth - 100, $nHeight - 40, 80, 30)
GUICtrlSetOnEvent (-1, "CloseForm")
GUISetState(#SW_SHOW) ;, $nForm)
$nPID = Run(#ComSpec & " /C " & $sCmd, ".", #SW_HIDE, $STDOUT_CHILD)
; $nPID = Run(#ComSpec & " /C _RunErrl.bat " & $sCmd, ".", #SW_HIDE, $STDOUT_CHILD) ; # Con ésto devuelve el errorlevel en _ERRL.TMP
While 1
$sLine = StdoutRead($nPID)
If #error Then ExitLoop
If StringLen ($sLine) > 0 then
$sLine = StringReplace ($sLine, Chr(13), "|")
$sLine = StringReplace ($sLine, Chr(10), "")
if StringLeft($sLine, 1)="|" Then
$sLine = " " & $sLine
endif
GUICtrlSetData ($nList, $sLine)
_GUICtrlListSelectIndex ($nList, _GUICtrlListCount ($nList) - 1)
EndIf
Wend
$sLine = " ||"
GUICtrlSetData ($nList, $sLine)
_GUICtrlListSelectIndex ($nList, _GUICtrlListCount ($nList) - 1)
GUICtrlSetData ($nClose, $sButDone)
WinSetTitle ($sTitRun, "", $sTitDone)
If $sSound <> "" Then
SoundPlay ($sSound)
EndIf
$rInfo = DllStructCreate("uint;dword") ; # LASTINPUTINFO
DllStructSetData($rInfo, 1, DllStructGetSize($rInfo));
DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($rInfo))
$nLastInput = DllStructGetData($rInfo, 2)
$nTime = TimerInit()
While 1
If $nAutoTimeout > 0 Then
DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($rInfo))
If DllStructGetData($rInfo, 2) <> $nLastInput Then
; Tocó una tecla
$nAutoTimeout = 0
EndIf
EndIf
If $nAutoTimeout > 0 And TimerDiff ($nTime) > $nAutoTimeOut * 1000 Then
ExitLoop
EndIf
Sleep (100)
Wend
Func CloseForm()
Exit
EndFunc
.NET has a pretty straight forward way to read and watch STDOUT.
I guess this would be the cleanest way, since it is not dependent on any external files, just the path to rsync. I would not be too surprised if there is a wrapper library out there either. If not, write and open source it :)
I've built my own simple object for this, I get a lot of reuse out of it, I can wrap it with a cmdline, web page, webservice, write output to a file, etc---
The commented items contain some rsync examples--
what I'd like to do sometime is embed rsync (and cygwin) into a resource & make a single .net executable out of it--
Here you go:
Imports System.IO
Namespace cds
Public Class proc
Public _cmdString As String
Public _workingDir As String
Public _arg As String
Public Function basic() As String
Dim sOut As String = ""
Try
'Set start information.
'Dim startinfo As New ProcessStartInfo("C:\Program Files\cwRsync\bin\rsync", "-avzrbP 192.168.42.6::cdsERP /cygdrive/s/cdsERP_rsync/gwy")
'Dim startinfo As New ProcessStartInfo("C:\Program Files\cwRsync\bin\rsync", "-avzrbP 10.1.1.6::user /cygdrive/s/cdsERP_rsync/gws/user")
'Dim startinfo As New ProcessStartInfo("C:\windows\system32\cscript", "//NoLogo c:\windows\system32\prnmngr.vbs -l")
Dim si As New ProcessStartInfo(_cmdString, _arg)
si.UseShellExecute = False
si.CreateNoWindow = True
si.RedirectStandardOutput = True
si.RedirectStandardError = True
si.WorkingDirectory = _workingDir
' Make the process and set its start information.
Dim p As New Process()
p.StartInfo = si
' Start the process.
p.Start()
' Attach to stdout and stderr.
Dim stdout As StreamReader = p.StandardOutput()
Dim stderr As StreamReader = p.StandardError()
sOut = stdout.ReadToEnd() & ControlChars.NewLine & stderr.ReadToEnd()
'Dim writer As New StreamWriter("out.txt", FileMode.CreateNew)
'writer.Write(sOut)
'writer.Close()
stdout.Close()
stderr.Close()
p.Close()
Catch ex As Exception
sOut = ex.Message
End Try
Return sOut
End Function
End Class
End Namespace
Check out DeltaCopy. It is a Windows GUI for rsync.
Check NAsBackup Its open source software that give Windows user Rsync GUI using Watch STDOUT.

Resources